>>> 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()は1つのセットのみを返します。実際には次のように返されます。
[('NORTHLANDER', 3), ('VOLT', 3)]
この効果のための組み込み関数はありますか?
これは、最初に最小値を計算し、次に最小値を持つすべてのタプルを収集する単純な2段階のソリューションなので、これを行うための独自の関数を記述します。これはかなり特殊な操作であり、汎用min()機能に期待されるものではありません。
最小値の要素を見つけます。
>>> lstm = min([x for x in lst if x[1] > 0], key = lambda x: x[1])
>>> lstm
('NORTHLANDER', 3)
list次に、値が次の値である要素を取得して、新しいリストを作成しlstmます。
>>> [y for y in lst if y[1] == lstm[1]]
[('NORTHLANDER', 3), ('VOLT', 3)]
使用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
つまり、defaultdict2倍以上速いようです。
@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
collections.Counter?同様のデータを処理するために設計されています。
# 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)]
(これは単なるアイデアであり、効率を上げることを目的としたものではありません)
独自の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)]