जवाबों:
आप एक जनरेटर अभिव्यक्ति का उपयोग कर सकते हैं :
>>> 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'}
यदि आपको उस आइटम को संभालने की आवश्यकता नहीं है जो वहां नहीं है, तो आप वह कर सकते हैं जो उपयोगकर्ता मैट ने अपनी टिप्पणी में सुझाया है और थोड़ा अलग उपयोग करके डिफ़ॉल्ट प्रदान करें:
next((item for item in dicts if item["name"] == "Pam"), None)
और आइटम के सूचकांक को खोजने के लिए, आइटम के बजाय, आप सूची को गणना () कर सकते हैं :
next((i for i, item in enumerate(dicts) if item["name"] == "Pam"), None)
[item for item in dicts if item["name"] == "Pam"][0]
?
enumerate()
एक रनिंग इंडेक्स जेनरेट करने के लिए जोड़ें next(i for i, item in enumerate(dicts) if item["name"] == "Pam")
:।
यह मुझे सबसे अधिक आकर्षक लगता है:
people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]
filter(lambda person: person['name'] == 'Pam', people)
परिणाम (पायथन 2 में एक सूची के रूप में लौटा):
[{'age': 7, 'name': 'Pam'}]
नोट: पायथन 3 में, एक फ़िल्टर ऑब्जेक्ट वापस आ गया है। तो python3 समाधान होगा:
list(filter(lambda person: person['name'] == 'Pam', people))
len()
, तो आपको list()
पहले परिणाम पर कॉल करना होगा। या: stackoverflow.com/questions/19182188/…
r
एक हैlist
next(filter(lambda x: x['name'] == 'Pam', dicts))
@ Frédéric Hamidi का जवाब बहुत अच्छा है। पाइथन में 3. .next()
थोड़ा-बहुत बदलाव के लिए सिंटैक्स । इस प्रकार एक मामूली संशोधन:
>>> 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 द्वारा टिप्पणियों में बताया गया है, आप इस तरह से एक डिफ़ॉल्ट मान जोड़ सकते हैं:
>>> 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
>>>
आप एक सूची समझ का उपयोग कर सकते हैं :
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
मैंने शब्दकोशों की एक सूची के माध्यम से जाने और उन शब्दकोशों को वापस करने के लिए विभिन्न तरीकों का परीक्षण किया जहां कुंजी x का एक निश्चित मूल्य है।
परिणाम:
पायथन 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
परिणाम:
1.7303 # normal list iteration
1.3849 # generator expression
1.3158 # list comprehension
7.7848 # filter
@ Frédéric Hamidi में बस थोड़ा सा जोड़ने के लिए।
मामले में आप सुनिश्चित नहीं हैं कि एक कुंजी dicts की सूची में है, कुछ इस तरह से मदद करेगा:
next((item for item in dicts if item.get("name") and item["name"] == "Pam"), None)
item.get("name") == "Pam"
क्या आपने कभी पांडा पैकेज की कोशिश की है? यह इस तरह के खोज कार्य के लिए एकदम सही है और अनुकूलित भी है।
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) ]
मैंने बड़े पैमाने पर पांडा के तेज़ रनटाइम्स यानी 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]
ये एक तरीका है...
आप इसे पायथन में फ़िल्टर और अगले तरीकों के उपयोग से प्राप्त कर सकते हैं।
filter
विधि दिए गए अनुक्रम को फ़िल्टर करती है और एक पुनरावृत्ति देता है।
next
विधि एक पुनरावृत्ति स्वीकार करता है और सूची में अगला तत्व देता है।
तो आप तत्व को पा सकते हैं,
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)
और आउटपुट है,
{'name': 'Pam', 'age': 7}
नोट: उपरोक्त कोड None
अगर हम खोज रहे हैं तो नाम वापस नहीं मिलेगा ।
मेरा पहला विचार यह होगा कि आप इन शब्दकोशों का एक शब्दकोश बनाने पर विचार करना चाह सकते हैं ... यदि, उदाहरण के लिए, आप इसे छोटी संख्या से अधिक बार खोज रहे हैं।
हालाँकि यह एक समय से पहले का अनुकूलन हो सकता है। इसमें क्या गलत होगा:
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'}
आप यह कोशिश कर सकते हैं:
''' 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'}
यहाँ थ्रॉहग सूची का उपयोग करते हुए एक तुलना की जाती है, फ़िल्टर + लैम्ब्डा या रीफैक्टरिंग (यदि आपके मामले में आवश्यक या वैध है) का उपयोग करते हुए आपका कोड डिक्सेस की सूची के बजाय डिक्ट्स के हुक्म के लिए है
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
और आउटपुट यह है:
List of Dictionries took: 0.0099310874939
Using filter took: 0.0121960639954
Dict of Dicts took: 4.05311584473e-06
निष्कर्ष: स्पष्ट रूप से डिक्सेस का शब्दकोश होना उन मामलों में खोज करने में सक्षम होने के लिए सबसे कुशल तरीका है, जहां आप जानते हैं कि आप केवल आईडी द्वारा खोज रहे होंगे। दिलचस्प रूप से फ़िल्टर का उपयोग सबसे धीमा समाधान है।
आपको सूची के सभी तत्वों से गुजरना होगा। कोई शॉर्टकट नहीं है!
जब तक कहीं और आप सूची के आइटम की ओर इशारा करते हुए नामों का एक शब्दकोश रखते हैं, लेकिन तब आपको अपनी सूची से एक तत्व को पॉप करने के परिणामों का ध्यान रखना होगा।
मुझे यह धागा तब मिला जब मैं उसी प्रश्न का उत्तर खोज रहा था। जब मुझे पता चलता है कि यह एक देर से जवाब है, तो मुझे लगा कि मैं इसे किसी और के लिए उपयोगी होने पर योगदान दूंगा:
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
यहां प्रस्तावित अधिकांश (यदि सभी नहीं) कार्यान्वयन में दो दोष हैं:
एक अद्यतन प्रस्ताव:
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)
शायद सबसे अधिक पायथोनिक नहीं है, लेकिन कम से कम थोड़ा और अधिक असफल।
उपयोग:
>>> 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}
द गित ।