Python列表中的字典search
假设我有这个:
[ {"name": "Tom", "age": 10}, {"name": "Mark", "age": 5}, {"name": "Pam", "age": 7} ]
并search“Pam”作为名字,我想检索相关词典:{name:“Pam”,年龄:7)
如何做到这一点?
你可以使用一个生成器expression式 :
>>> dicts = [ ... { "name": "Tom", "age": 10 }, ... { "name": "Mark", "age": 5 }, ... { "name": "Pam", "age": 7 }, ... { "name": "Dick", "age": 12 } ... ] >>> (item for item in dicts if item["name"] == "Pam").next() {'age': 7, 'name': 'Pam'}
这在我看来是最pythonic的方式:
people = [ {'name': "Tom", 'age': 10}, {'name': "Mark", 'age': 5}, {'name': "Pam", 'age': 7} ] filter(lambda person: person['name'] == 'Pam', people)
结果:
[{'age': 7, 'name': 'Pam'}]
你可以使用列表理解 :
def search(name, people): return [element for element in people if element['name'] == name]
FrédéricHamidi的答案很棒。 在Python 3.x中, .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 >>>
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")
这是在字典列表中search值的一般方法:
def search_dictionaries(key, value, list_of_dictionaries): return [element for element in list_of_dictionaries if element[key] == value]
给@FrédéricHamidi添加一点点。
如果你不确定密钥是否在列表中,像这样的东西将有助于:
next((item for item in dicts if item.get("name") and item["name"] == "Pam"), None)
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]
这是一个方法…
我的第一个想法是,你可能会考虑创build一个这些字典的字典…例如,如果你将要比less数几次search更多。
不过这可能是一个不成熟的优化。 什么是错的:
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]
你有没有试过pandas包? 这对于这种search任务来说也是完美的,并且也被优化了。
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) ]
我在下面添加了一些基准,来说明大pandas在更大规模上的更快的运行时间,例如10万条logging:
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
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'}
这里是使用迭代throuhg列表比较,使用筛选器+ lambda或重构(如果需要或有效的你的情况)你的代码字典而不是列表字典
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
结论:显然有一个字典的字典是能够在这些情况下search最有效的方式,你知道你会被id的唯一search。 有趣的是使用filter是最慢的解决scheme。
你必须通过列表中的所有元素。 没有捷径!
除非你在其他地方保留了一个名字指向列表项的字典,但是你必须注意从列表中popup一个元素的后果。