在词典列表中搜索键值

2024-10-04 05:21:56 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个列表l,包含多个字典l = [ d1, d2, ...., d100],其中每个字典都用键'id''address''price'定义。 现在,我想从列表l中获取所有字典d,其中键'price'的值等于50。有没有比使用for循环更快的方法呢?这个处理已经封装在other for loop函数中,所以如果可能的话,我不希望有两个for loop。 函数的框架现在看起来如下:

for ... (external for loop):
    results = []
    for d in l:
        if d['price'] == 50:
           results.append(d)

Tags: 方法函数loopid列表for字典定义
3条回答

除非你知道列表的结构(例如按价格排序,或者只有三个项目可以有这样的价格),否则我们不能使算法比线性时间快。所以无论如何我们必须循环。你知道吗

列表理解

我们可以使用列表理解,例如:

[d for d in l if d.get('price') == 50]

(这也会过滤掉没有price属性的字典)。你知道吗

熊猫

我们也可以用熊猫。Pandas是一个高效的数据帧库,在数据量很大的情况下,它的性能往往优于Python循环。在这种情况下,我们可以在datframe中加载字典,对其执行过滤,然后检索字典列表。请注意,这些将是不同的字典(即包含相同数据的其他对象)。因此数据被“复制”。你知道吗

import pandas as pd
df = pd.DataFrame(l)
result = list(df[df.price == 50].T.to_dict().values())

所以这里我们用df.price == 50过滤。请注意,在窗帘后面有一些用于过滤的回路。你知道吗

这也是一种更具声明性的方法:代码更多地解释了它在做什么,而不是如何。如何过滤并不是您的问题,语法相当优雅地显示您正在过滤数据。你知道吗

您可以使用list comprehension

results = [d for d in l if d['price'] == 50]

这在算法上与循环没有什么不同(它还必须迭代整个列表),但是理解是用C优化的,因此速度更快。另一种选择是使results成为惰性迭代器:

# generator expression
results = (d for d in l if d['price'] == 50)

# filter (not the most elegant/readable with lambda)
results = filter(lambda d: d['price'] == 50, l)

这将不会在声明时迭代list。它只在您迭代results(您只能这样做一次)时才会这样做。如果您不总是或只是部分地需要迭代results,这可能会有所帮助。你知道吗

使用列表理解

你不会错的。

我探索了以下方法:

  1. 基本for循环
  2. 用if比较列出理解
  3. 带lambda表达式的内置筛选器函数
  4. 列表生成器

Python2.7.12和Python3.5.2(不是最新版本)探讨了这些方法。在Python2中,最好的方法是方法4,而在Python3中,最好的方法是方法2(至少对于我的版本来说,它也不是最新的)。你知道吗

以下是Python 2.7.12的结果:

# 2.7.12
# [GCC 5.4.0 20160609]
# Method 1 found 496 item in 0.382161 seconds. (basic for-loop)
# Method 2 found 496 item in 0.365456 seconds. (list comprehension)
# Method 3 found 496 item in 0.565614 seconds. (built in filter function)
# Method 4 found 496 item in 0.273335 seconds. (list comprehension over a generator expression)

以下是Python 3.5.2的结果:

# 3.5.2 
# [GCC 5.4.0 20160609]
# Method 1 found 493 item in 0.500266 seconds. (basic for-loop)
# Method 2 found 493 item in 0.338361 seconds. (list comprehension)
# Method 3 found 493 item in 0.796027 seconds. (built in filter function)
# Method 4 found 493 item in 0.351668 seconds. (list comprehension over a generator expression)

以下是用于获取结果的代码:

import time
import random
import sys

print(sys.version)

l = []
for i in range(10000):
    d = {'price': random.randint(40, 60), 'id': i}
    l.append(d)

#METHOD 1 - basic for-loop
start = time.time()
for _ in range(1000):
    results = []
    for d in l:
        if d['price'] == 50:
           results.append(d)
end = time.time()
print("Method 1 found {} item in {:f} seconds. (basic for-loop)".format(len(results), (end - start)))

#METHOD 2 - list comp with if statement
start = time.time()
results = []
for _ in range(1000):
    results = []
    results = [d for d in l if d['price'] == 50]
end = time.time()
print("Method 2 found {} item in {:f} seconds. (list comprehension)".format(len(results), (end - start)))

#METHOD 3 - using filter and a lambda expression
start = time.time()
results = []
for _ in range(1000):
    results = []
    results = list(filter(lambda d: d['price'] == 50, l))
end = time.time()
print("Method 3 found {} item in {:f} seconds. (built in filter function)".format(len(results), (end - start)))

#METHOD 4 - list comp over generator expression
start = time.time()
results = []
once = True
for _ in range(1000):
    results = []
    genResults = (d for d in l if d['price'] == 50)
    results = [it for it in genResults]
end = time.time()
print("Method 4 found {} item in {:f} seconds. (list comprehension over a generator expression)".format(len(results), (end - start))) 

相关问题 更多 >