Jawaban:
Anda dapat menggunakan ekspresi generator :
>>> 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'}
Jika Anda perlu untuk menangani item tidak berada di sana, maka Anda dapat melakukan apa yang pengguna Matt disarankan dalam komentarnya dan memberikan default menggunakan API yang sedikit berbeda:
next((item for item in dicts if item["name"] == "Pam"), None)
Dan untuk menemukan indeks item, daripada item itu sendiri, Anda dapat menghitung () daftar:
next((i for i, item in enumerate(dicts) if item["name"] == "Pam"), None)
[item for item in dicts if item["name"] == "Pam"][0]
?
enumerate()
untuk menghasilkan indeks berjalan: next(i for i, item in enumerate(dicts) if item["name"] == "Pam")
.
Ini bagi saya cara yang paling pythonic:
people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]
filter(lambda person: person['name'] == 'Pam', people)
hasil (dikembalikan sebagai daftar di Python 2):
[{'age': 7, 'name': 'Pam'}]
Catatan: Dalam Python 3, objek filter dikembalikan. Jadi solusi python3 adalah:
list(filter(lambda person: person['name'] == 'Pam', people))
len()
, Anda harus memanggil list()
hasilnya terlebih dahulu. Atau: stackoverflow.com/questions/19182188/…
r
adalahlist
next(filter(lambda x: x['name'] == 'Pam', dicts))
Jawaban @ Frédéric Hamidi luar biasa. Dalam Python 3.x sintaks untuk .next()
sedikit berubah. Jadi sedikit modifikasi:
>>> 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'}
Seperti yang disebutkan dalam komentar oleh @Matt, Anda dapat menambahkan nilai default seperti:
>>> 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
>>>
Anda dapat menggunakan pemahaman daftar :
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
Saya menguji berbagai metode untuk menelusuri daftar kamus dan mengembalikan kamus di mana kunci x memiliki nilai tertentu.
Hasil:
Semua tes dilakukan dengan Python 3.6 .4, W7x64.
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
Hasil:
1.7303 # normal list iteration
1.3849 # generator expression
1.3158 # list comprehension
7.7848 # filter
Untuk menambahkan sedikit saja ke @ FrédéricHamidi.
Jika Anda tidak yakin kunci ada dalam daftar dicts, sesuatu seperti ini akan membantu:
next((item for item in dicts if item.get("name") and item["name"] == "Pam"), None)
item.get("name") == "Pam"
Pernahkah Anda mencoba paket panda? Ini sempurna untuk tugas pencarian semacam ini dan juga dioptimalkan.
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) ]
Saya telah menambahkan sedikit pembandingan di bawah ini untuk mengilustrasikan runtime lebih cepat panda pada skala yang lebih besar yaitu entri 100k +:
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]
Ini adalah salah satu cara ...
Anda dapat mencapai ini dengan menggunakan filter dan metode selanjutnya dengan Python.
filter
metode menyaring urutan yang diberikan dan mengembalikan iterator.
next
Metode menerima iterator dan mengembalikan elemen berikutnya dalam daftar.
Jadi Anda dapat menemukan elemen dengan,
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)
dan hasilnya adalah,
{'name': 'Pam', 'age': 7}
Catatan: Kode di atas akan kembali None
memetikan jika nama yang kita cari tidak ditemukan.
Pikiran pertama saya adalah Anda mungkin ingin mempertimbangkan membuat kamus kamus ini ... jika, misalnya, Anda akan mencarinya lebih dari beberapa kali.
Namun itu mungkin merupakan optimasi prematur. Apa yang salah dengan:
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'}
Anda dapat mencoba ini:
''' 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'}
Berikut ini adalah perbandingan menggunakan daftar iterating throuhg, menggunakan filter + lambda atau refactoring (jika diperlukan atau valid untuk kasus Anda) kode Anda untuk dict dicts daripada daftar dicts
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
Dan hasilnya adalah ini:
List of Dictionries took: 0.0099310874939
Using filter took: 0.0121960639954
Dict of Dicts took: 4.05311584473e-06
Kesimpulan: Jelas memiliki kamus dicts adalah cara yang paling efisien untuk dapat mencari dalam kasus-kasus itu, di mana Anda tahu mengatakan Anda akan mencari dengan id saja. Menariknya menggunakan filter adalah solusi paling lambat.
Anda harus melalui semua elemen daftar. Tidak ada jalan pintas!
Kecuali di tempat lain Anda menyimpan kamus dari nama-nama yang menunjuk ke item-item dari daftar, tetapi kemudian Anda harus berhati-hati dengan konsekuensi memunculkan elemen dari daftar Anda.
Saya menemukan utas ini ketika saya mencari jawaban untuk pertanyaan yang sama. Sementara saya menyadari bahwa ini adalah jawaban yang terlambat, saya pikir saya akan berkontribusi jika itu berguna bagi orang lain:
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
Sebagian besar (jika tidak semua) implementasi yang diusulkan di sini memiliki dua kelemahan:
Proposisi yang diperbarui:
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)
Mungkin bukan yang paling pythonic, tapi setidaknya sedikit lebih aman.
Pemakaian:
>>> 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}
The Inti .