提高迭代python中列表集的效率

时间:2016-01-27 19:17:36

标签: python python-2.7

我有一个列表列表,其中元素0中的项目与元素1中的值相关联。每个项目可能出现多次。我想创建一个唯一项目列表,其中每个项目的最大值都与之相关。我的代码实现了这一点,但似乎非常低效。此外,这是一个简化的例子。 mylist可能是100,000行。有关提高效率的建议吗?

mylist = [['Item 1', 12],['Item 1', 10], ['Item 3', 12],['Item 4', 10], ['Item 3', 14]]

# get unique items
my_unique_items = list(set(x[0] for x in mylist))

# make it a list of list
my_unique_items = [[x] for x in my_unique_items]

# iterate over list items
for item in my_unique_items:

    # do list comp to get max value and append
    item.append(max([x[1] for x in mylist if x[0] == item[0]]))

print my_unique_items

3 个答案:

答案 0 :(得分:1)

仅循环mylist一次会更有效率。如果您只关心每个项目键的最大值,只需保留项目及其最大值的映射,并在列表中进行比较。

这是最糟糕的O(n)情况,而你的原始情况最糟糕的是O(n ^ 2)。

item_maxes = {}
for item in mylist:
    max_value = item_maxes.setdefault(item[0], None)
    if max_value is None or item[1] > max_value:
        item_maxes[item[0]] = item[1]

编辑:我认为此方法的ShadowRanger's版本看起来更清晰:

max_vals = {}
for item, value in mylist:
    max_vals[item] = max(max_vals.get(item, value), value)

答案 1 :(得分:1)

如果输入已经排序(或者您希望输出排序),那么使用itertools.groupby的方法很好:

from future_builtins import map  # On Python 2.x only, to get generator based map

from itertools import groupby
from operator import itemgetter

# Nicer names, and avoid recreating getvalue on each loop
getitem, getvalue = itemgetter(0), itemgetter(1)

# If not already sorted, must sort by same key we're grouping on:
mylist.sort(key=getitem)

max_vals = [(k, max(map(getvalue, g))) for k, g in groupby(mylist, key=getitem)]

如果您不关心订单,并且您的商品是可清洗的,dict通常会更快(如果大多数items是唯一的,则可能会使用更多的内存):

max_vals = {}
for item, value in mylist:
    max_vals[item] = max(max_vals.get(item, value), value)

答案 2 :(得分:0)

使用itertools模块中的groupbyoperator模块中的itemgetter

>>> from itertools import groupby
>>> from operator import itemgetter
>>> d = {}
>>> for g, data in groupby(sorted(mylist, key=itemgetter(0)), key=itemgetter(0)):
...     d[g] = max(list(zip(*data))[1])
... 
>>> d
{'Item 1': 12, 'Item 3': 14, 'Item 4': 10}

您也可以使用itertools.islice,而不是使用list构造函数和普通切片操作。

>>> for g, data in groupby(sorted(mylist, key=itemgetter(0)), key=itemgetter(0)):
...     d[g] = max(*islice(zip(*data),  1, None))
... 
>>> d
{'Item 1': 12, 'Item 3': 14, 'Item 4': 10}