Yanıtlar:
Bir jeneratör ifadesi kullanabilirsiniz :
>>> dicts = [
... { "name": "Tom", "age": 10 },
... { "name": "Mark", "age": 5 },
... { "name": "Pam", "age": 7 },
... { "name": "Dick", "age": 12 }
... ]
>>> next(item for item in dicts if item["name"] == "Pam")
{'age': 7, 'name': 'Pam'}
Öğenin orada bulunmamasıyla ilgilenmeniz gerekiyorsa, Matt'in yorumunda önerdiği kullanıcıyı yapabilir ve biraz farklı bir API kullanarak bir varsayılan sağlayabilirsiniz:
next((item for item in dicts if item["name"] == "Pam"), None)
Ve öğenin kendisini değil, öğenin dizinini bulmak için listeyi numaralandırabilir () :
next((i for i, item in enumerate(dicts) if item["name"] == "Pam"), None)
[item for item in dicts if item["name"] == "Pam"][0]
?
enumerate()
çalışan bir indeks oluşturmak için: next(i for i, item in enumerate(dicts) if item["name"] == "Pam")
.
Bu bana en pitonik bir şekilde bakıyor:
people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]
filter(lambda person: person['name'] == 'Pam', people)
sonuç (Python 2'de liste olarak döndürülür):
[{'age': 7, 'name': 'Pam'}]
Not: Python 3'te bir filtre nesnesi döndürülür. Yani python3 çözümü:
list(filter(lambda person: person['name'] == 'Pam', people))
len()
istiyorsanız list()
, önce sonucu çağırmanız gerekir . Veya: stackoverflow.com/questions/19182188/…
r
a,list
next(filter(lambda x: x['name'] == 'Pam', dicts))
@ Frédéric Hamidi'nin cevabı harika. Python 3.x'te sözdizimi .next()
biraz değişti. Böylece küçük bir değişiklik:
>>> dicts = [
{ "name": "Tom", "age": 10 },
{ "name": "Mark", "age": 5 },
{ "name": "Pam", "age": 7 },
{ "name": "Dick", "age": 12 }
]
>>> next(item for item in dicts if item["name"] == "Pam")
{'age': 7, 'name': 'Pam'}
@Matt tarafından yapılan yorumlarda belirtildiği gibi, varsayılan bir değer ekleyebilirsiniz:
>>> next((item for item in dicts if item["name"] == "Pam"), False)
{'name': 'Pam', 'age': 7}
>>> next((item for item in dicts if item["name"] == "Sam"), False)
False
>>>
Bir liste kavrayışı kullanabilirsiniz :
def search(name, people):
return [element for element in people if element['name'] == name]
people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]
def search(name):
for p in people:
if p['name'] == name:
return p
search("Pam")
def search(list, key, value): for item in list: if item[key] == value: return item
Sözlükler listesini gözden geçirmek ve x anahtarının belirli bir değere sahip olduğu sözlükleri döndürmek için çeşitli yöntemleri test ettim.
Sonuçlar:
Tüm testler Python 3.6 .4, W7x64 ile yapılmıştır.
from random import randint
from timeit import timeit
list_dicts = []
for _ in range(1000): # number of dicts in the list
dict_tmp = {}
for i in range(10): # number of keys for each dict
dict_tmp[f"key{i}"] = randint(0,50)
list_dicts.append( dict_tmp )
def a():
# normal iteration over all elements
for dict_ in list_dicts:
if dict_["key3"] == 20:
pass
def b():
# use 'generator'
for dict_ in (x for x in list_dicts if x["key3"] == 20):
pass
def c():
# use 'list'
for dict_ in [x for x in list_dicts if x["key3"] == 20]:
pass
def d():
# use 'filter'
for dict_ in filter(lambda x: x['key3'] == 20, list_dicts):
pass
Sonuçlar:
1.7303 # normal list iteration
1.3849 # generator expression
1.3158 # list comprehension
7.7848 # filter
@ FrédéricHamidi'ye sadece küçük bir parça eklemek için.
Bir anahtarın dikteler listesinde olduğundan emin değilseniz, bunun gibi bir şey yardımcı olacaktır:
next((item for item in dicts if item.get("name") and item["name"] == "Pam"), None)
item.get("name") == "Pam"
Panda paketini hiç denediniz mi? Bu tür bir arama görevi için mükemmeldir ve optimize edilmiştir.
import pandas as pd
listOfDicts = [
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]
# Create a data frame, keys are used as column headers.
# Dict items with the same key are entered into the same respective column.
df = pd.DataFrame(listOfDicts)
# The pandas dataframe allows you to pick out specific values like so:
df2 = df[ (df['name'] == 'Pam') & (df['age'] == 7) ]
# Alternate syntax, same thing
df2 = df[ (df.name == 'Pam') & (df.age == 7) ]
Pandaların daha hızlı çalışma sürelerini 100k + girişlerle daha hızlı bir şekilde göstermek için aşağıya biraz kıyaslama ekledim:
setup_large = 'dicts = [];\
[dicts.extend(({ "name": "Tom", "age": 10 },{ "name": "Mark", "age": 5 },\
{ "name": "Pam", "age": 7 },{ "name": "Dick", "age": 12 })) for _ in range(25000)];\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(dicts);'
setup_small = 'dicts = [];\
dicts.extend(({ "name": "Tom", "age": 10 },{ "name": "Mark", "age": 5 },\
{ "name": "Pam", "age": 7 },{ "name": "Dick", "age": 12 }));\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(dicts);'
method1 = '[item for item in dicts if item["name"] == "Pam"]'
method2 = 'df[df["name"] == "Pam"]'
import timeit
t = timeit.Timer(method1, setup_small)
print('Small Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_small)
print('Small Method Pandas: ' + str(t.timeit(100)))
t = timeit.Timer(method1, setup_large)
print('Large Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_large)
print('Large Method Pandas: ' + str(t.timeit(100)))
#Small Method LC: 0.000191926956177
#Small Method Pandas: 0.044392824173
#Large Method LC: 1.98827004433
#Large Method Pandas: 0.324505090714
names = [{'name':'Tom', 'age': 10}, {'name': 'Mark', 'age': 5}, {'name': 'Pam', 'age': 7}]
resultlist = [d for d in names if d.get('name', '') == 'Pam']
first_result = resultlist[0]
Bu bir yol ...
Bunu Python'da filtre ve sonraki yöntemlerle yapabilirsiniz.
filter
yöntemi verilen diziyi filtreler ve bir yineleyici döndürür.
next
yöntemi bir yineleyici kabul eder ve listedeki bir sonraki öğeyi döndürür.
Böylece elementi şu şekilde bulabilirsiniz:
my_dict = [
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]
next(filter(lambda obj: obj.get('name') == 'Pam', my_dict), None)
ve çıktı,
{'name': 'Pam', 'age': 7}
Not: None
Aradığınız kod bulunamazsa, yukarıdaki kod olayla sonuçlanır.
İlk düşüncem, bu sözlüklerden bir sözlük oluşturmayı düşünmek isteyebileceğinizdir ... örneğin, eğer az sayıda kez aradıysanız.
Ancak bu erken bir optimizasyon olabilir. Sorun ne olabilir:
def get_records(key, store=dict()):
'''Return a list of all records containing name==key from our store
'''
assert key is not None
return [d for d in store if d['name']==key]
dicts=[
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]
from collections import defaultdict
dicts_by_name=defaultdict(list)
for d in dicts:
dicts_by_name[d['name']]=d
print dicts_by_name['Tom']
#output
#>>>
#{'age': 10, 'name': 'Tom'}
Bunu deneyebilirsiniz:
''' lst: list of dictionaries '''
lst = [{"name": "Tom", "age": 10}, {"name": "Mark", "age": 5}, {"name": "Pam", "age": 7}]
search = raw_input("What name: ") #Input name that needs to be searched (say 'Pam')
print [ lst[i] for i in range(len(lst)) if(lst[i]["name"]==search) ][0] #Output
>>> {'age': 7, 'name': 'Pam'}
Burada, yineleme listesi yerine dikteleri dikte etmek için filtre + lambda veya yeniden kodlama (durumunuz için geçerliyse veya durumunuz için geçerliyse) kullanarak yinelenen throuhg listesini kullanan bir karşılaştırma
import time
# Build list of dicts
list_of_dicts = list()
for i in range(100000):
list_of_dicts.append({'id': i, 'name': 'Tom'})
# Build dict of dicts
dict_of_dicts = dict()
for i in range(100000):
dict_of_dicts[i] = {'name': 'Tom'}
# Find the one with ID of 99
# 1. iterate through the list
lod_ts = time.time()
for elem in list_of_dicts:
if elem['id'] == 99999:
break
lod_tf = time.time()
lod_td = lod_tf - lod_ts
# 2. Use filter
f_ts = time.time()
x = filter(lambda k: k['id'] == 99999, list_of_dicts)
f_tf = time.time()
f_td = f_tf- f_ts
# 3. find it in dict of dicts
dod_ts = time.time()
x = dict_of_dicts[99999]
dod_tf = time.time()
dod_td = dod_tf - dod_ts
print 'List of Dictionries took: %s' % lod_td
print 'Using filter took: %s' % f_td
print 'Dict of Dicts took: %s' % dod_td
Ve çıktı şudur:
List of Dictionries took: 0.0099310874939
Using filter took: 0.0121960639954
Dict of Dicts took: 4.05311584473e-06
Sonuç: Açıkçası bir dikte sözlüğüne sahip olmak, sadece kimliklerle arama yapacağınızı bildiğiniz bu durumlarda arama yapmanın en etkili yoludur. ilginç bir şekilde filtre kullanmak en yavaş çözümdür.
Burada önerilen uygulamaların çoğunun (hepsi olmasa da) iki kusuru vardır:
Güncellenmiş bir teklif:
def find_first_in_list(objects, **kwargs):
return next((obj for obj in objects if
len(set(obj.keys()).intersection(kwargs.keys())) > 0 and
all([obj[k] == v for k, v in kwargs.items() if k in obj.keys()])),
None)
Belki en pitonik değil, en azından biraz daha güvenli.
Kullanımı:
>>> obj1 = find_first_in_list(list_of_dict, name='Pam', age=7)
>>> obj2 = find_first_in_list(list_of_dict, name='Pam', age=27)
>>> obj3 = find_first_in_list(list_of_dict, name='Pam', address='nowhere')
>>>
>>> print(obj1, obj2, obj3)
{"name": "Pam", "age": 7}, None, {"name": "Pam", "age": 7}
Özü .
Listenin tüm unsurlarını gözden geçirmelisiniz. Kısayol yok!
Başka bir yerde, listenin öğelerini işaret eden adların sözlüğünü tutmazsanız, ancak listenizden bir öğeyi açmanın sonuçlarına dikkat etmeniz gerekir.
Aynı soruya bir cevap ararken bu konuyu buldum. Geç bir cevap olduğunu fark etsem de, başkalarına faydalı olması durumunda katkıda bulunacağımı düşündüm:
def find_dict_in_list(dicts, default=None, **kwargs):
"""Find first matching :obj:`dict` in :obj:`list`.
:param list dicts: List of dictionaries.
:param dict default: Optional. Default dictionary to return.
Defaults to `None`.
:param **kwargs: `key=value` pairs to match in :obj:`dict`.
:returns: First matching :obj:`dict` from `dicts`.
:rtype: dict
"""
rval = default
for d in dicts:
is_found = False
# Search for keys in dict.
for k, v in kwargs.items():
if d.get(k, None) == v:
is_found = True
else:
is_found = False
break
if is_found:
rval = d
break
return rval
if __name__ == '__main__':
# Tests
dicts = []
keys = 'spam eggs shrubbery knight'.split()
start = 0
for _ in range(4):
dct = {k: v for k, v in zip(keys, range(start, start+4))}
dicts.append(dct)
start += 4
# Find each dict based on 'spam' key only.
for x in range(len(dicts)):
spam = x*4
assert find_dict_in_list(dicts, spam=spam) == dicts[x]
# Find each dict based on 'spam' and 'shrubbery' keys.
for x in range(len(dicts)):
spam = x*4
assert find_dict_in_list(dicts, spam=spam, shrubbery=spam+2) == dicts[x]
# Search for one correct key, one incorrect key:
for x in range(len(dicts)):
spam = x*4
assert find_dict_in_list(dicts, spam=spam, shrubbery=spam+1) is None
# Search for non-existent dict.
for x in range(len(dicts)):
spam = x+100
assert find_dict_in_list(dicts, spam=spam) is None