2017-03-08 4 views
2

私は簡単な作業でなければならないと感じていることを頭に入れようとしています。私はPython 3.4を使用しています。私はそれぞれ固有の名前に対応するすべての値の合計を取得しようとしています指定された条件の下でサブリストに含まれる値を集計する

newlist = [ ['John', 12],['Mary', 10],['Paul', 12],['Mary', 5],['Paul', 8],['John', 7] ] 

は、私はサブリスト(簡易版)が含まれ、次のリストを持っています。最速かつ/またはどのようになるか20

から15

ポール - 19

メアリー -

ジョン:だから、上記のリストに関して結果は、次のようなものをお読みくださいこれを達成する最も効率的な方法は?私自身の努力の

例は

は今、私はそうのように私の問題を解決した(しかし、言ったように:私は、より効率的なソリューションを探しています):

unique_names = [] 
for i in newlist: 
    if i[0] not in unique_names: 
     unique_names.append(i[0]) 

valuelist = [] 
for name in unique_names: 
    valuelist.append(name) 
    yet_another_list = [] 
    for i in newlist: 
     if name in i: 
      yet_another_list.append(i[1]) 
    valuelist.append(sum(yet_another_list)) 

EDIT

- 回答をテストしました -

わかりましたので、私はたくさんの回答を得ました。記録のために、私は提案されたソリューションのそれぞれに対して別々の機能を作成することによってそれらをテストしました。私はstart = time.perf_counter()end = time.perf_counter() - startを使って各関数の応答時間を計算しました。私はそれを必要とする各機能の中にインポートをカプセル化しました。

このテストに使用したリストには、3985個のサブリストが含まれていました。

結果は、5つの異なる実験から(4つの小数点以下を四捨五入)ここ

my_own_solution:0.9800/0.9703/0.9873/1.0023/0.9540

defaultdict try:0.0014/0.0016/0.0014/0.0018/0.0014

counter try:0.0030/0.0026/0.0026/0.0027/0.0026

reduce_try:0.0155/0.0153/0.0151/0.0149/0.0174

ittertry:(山車に失敗した)0.0242/0.0268/0.0239/0.0307/0.0259

valuelisttry:総合0.0018/0.0018/0.0019/0.0020/0.0043

、私は本当にdefaultdict文のシンプルさを感謝しています。これは、全体的に最速の選択肢でもあるようです。しかし、輸入を嫌う人にとっては、valuelist(または実際にはvalue dictionary)のオプションも良い選択のように思えます。

答えて

2

使用defaultdict

from collections import defaultdict 

values = defaultdict(int) 

for x, y in newlist: 
    values[x]+=y 

編集:ちょうど(defaultdictを使用INT )、intはすでに呼び出し可能です。私はそれを考えませんでした!

あなたが collections.Counterオブジェクトを使用することができます
+0

'int'はすでに呼び出し可能ですので、' lambda'にそれをラップする必要はありません。 – timgeb

+0

'defaultdict(int)'を実行するだけです。 –

0
valuelist = {} 
for (name, value) in newlist: 
    if name not in valuelist: 
    valuelist[name] = 0 
    valuelist[name] += value 

print (valuelist) 

{ 'ポール':20 'ジョン':19 'メアリー':15}

1

:あなたは1つのライナー(必ずしもではないが、より効率的か、読みやすい)あなたは functools.reduceを使用して、初期化子として Counterを渡すことができますに興味があれば

from collections import Counter 

c = Counter() 
for name, cnt in newlist: 
    c[name] += cnt 

print(c.items()) 
# [('Paul', 20), ('John', 19), ('Mary', 15)] 

from functools import reduce 

c = reduce(lambda x, y: x.update({y[0]: y[1]}) or x, newlist, Counter()) 
1

私はdefaultdictを使います。

>>> from collections import defaultdict 
>>> newlist = [ ['John', 12],['Mary', 10],['Paul', 12],['Mary', 5],['Paul', 8],['John', 7] ] 
>>> d = defaultdict(int) 
>>> for name, score in newlist: 
...  d[name] += score 
... 
>>> d 
defaultdict(<class 'int'>, {'Mary': 15, 'John': 19, 'Paul': 20}) 
0

最速のアプローチは、おそらくitertoolsからcollectionschainrepeatからCounterを伴うだろう:

from_it = chain.from_iterable 
c = Counter(from_it(repeat(i, j) for i,j in chain(newlist))) 

得どちら:

Counter({'John': 19, 'Mary': 15, 'Paul': 20}) 

文がfor i,j in chain(newlist)newlistからすべてのリストをアンパック文字列を送りますその回数だけそれを繰り返すために、そのカウント数がjからrepeatまでの(例えば、John)である。この理解は、(from_it)に渡されるので、Counterへの入力として供給することができます。

関連する問題