1
>>> lst
[('BFD', 0), ('NORTHLANDER', 3), ('HP', 23), ('VOLT', 3)]
>>> min([x for x in lst if x[1]!=0], key=lambda x: x[1])
('NORTHLANDER', 3)
>>>

这里 min() 只返回一组。它实际上应该返回:

[('NORTHLANDER', 3), ('VOLT', 3)]

有什么内置功能可以达到这种效果吗?

4

4 回答 4

8

这是一个简单的两步解决方案,首先计算最小值,然后收集所有具有最小值的元组,因此请编写自己的函数来执行此操作。这是一个相当专业的操作,而不是通用min()功能所期望的。

找到具有最小值的元素:

>>> lstm = min([x for x in lst if x[1] > 0], key = lambda x: x[1])
>>> lstm
('NORTHLANDER', 3)

然后只需形成一个新列表,list其中的值是 of 的元素lstm

>>> [y for y in lst if y[1] == lstm[1]]
[('NORTHLANDER', 3), ('VOLT', 3)]
于 2013-01-04T10:02:39.580 回答
1

使用collections.defaultdict

d=collections.defaultdict(list)
for item in lst:
    d[item[1]].append(item)
d[min(key for key in d.keys() if key!=0)]

出去:

[('NORTHLANDER', 3), ('VOLT', 3)]

测试

#unwind's solution

def f(lst):
    return [y for y in lst if y[1] == min([x for x in lst if x[1] > 0],
                                             key = lambda x: x[1])[1]]

def f2(lst):
    d=collections.defaultdict(list)
    for item in lst:
        d[item[1]].append(item)
    return d[min(key for key in d.keys() if key!=0)]

%timeit f(lst)
100000 loops, best of 3: 12.1 us per loop
%timeit f2(lst)
100000 loops, best of 3: 5.42 us per loop

所以,defaultdict似乎快了两倍多。

编辑 @martineau 优化:

def f3(lst):
    lstm = min((x for x in lst if x[1]), key = lambda x: x[1])[1]
    return [y for y in lst if y[1] == lstm]

%timeit f3(lst)
100000 loops, best of 3: 4.19 us per loop

另一个dict基于解决方案的使用set.default甚至更快:

def f4(lst):
    d={}
    for item in lst:
        if item[1] != 0:
            d.setdefault(item[1],{})[item]=0
    return d[min(d.keys())].keys()

%timeit f4(lst)
100000 loops, best of 3: 3.76 us per loop
于 2013-01-04T10:32:02.353 回答
0

您可以将自己的 multimin 函数编写为:

def multimin(seq, key=None):
    if key is None:
        key = lambda x: x
    min_e = min(seq, key=key)
    return filter((lambda x: key(x) == key(min_e)), seq)

例如:

>>> lst = [('BFD', 0), ('NORTHLANDER', 3), ('HP', 23), ('VOLT', 3)]
>>> print multimin([x for x in lst if x[1]!=0], key=lambda x: x[1]) 
[('NORTHLANDER', 3), ('VOLT', 3)]
于 2013-01-04T10:13:18.497 回答
0

集合。计数器?它专为处理类似数据而设计:

# Instantiate excluding zero length items
>>> c = collections.Counter({k: v for (k, v) in lst if v != 0})
>>> c
Counter({'HP': 23, 'NORTHLANDER': 3, 'VOLT': 3})

# Retrieve most common then reverse it
>>> least_common = c.most_common()[::-1]
[('VOLT', 3), ('NORTHLANDER', 3), ('HP', 23)]

>>> [(k,v) for (k,v) in least_common if v == least_common[0][1]]
[('VOLT', 3), ('NORTHLANDER', 3)]

(这只是一个想法,并不打算高效)

于 2013-01-04T10:09:41.127 回答