私は新しいPythonユーザーですが、条件の下でリスト要素を組み合わせる方法についてサポートが必要です。私はこのようなリストを持っています:
x = [['a', 10, 20], ['b', 10, 20], ['a', 20, 100]]
リスト内の同じ文字で始まるリスト要素を、他の要素を合計して結合したいと思います。たとえば、次のリストを取得したいと思いますx
。
x = [['a', 30, 120], ['b', 10, 20]]
どうすればこれを達成できますか?
itertools.groupby()を使用したワンライナー:
In [45]: lis=[['a', 10, 20], ['b', 10, 20], ['a', 20, 100]]
In [46]: lis.sort(key=itemgetter(0)) #sort the list first
In [47]: lis
Out[47]: [['a', 10, 20], ['a', 20, 100], ['b', 10, 20]]
In [49]: [[k]+map(sum,zip(*[x[1:] for x in g])) for k,g in groupby(lis,key=itemgetter(0))]
Out[49]: [['a', 30, 120], ['b', 10, 20]]
簡単な解決策:
In [23]: lis=[['a', 10, 20], ['b', 10, 20], ['a', 20, 100]]
In [24]: ans=[]
In [25]: lis.sort(key=itemgetter(0)) #sort the list according to the first elem
In [26]: lis
Out[26]: [['a', 10, 20], ['a', 20, 100], ['b', 10, 20]]
In [27]: for x in lis:
if ans:
if x[0]==ans[-1][0]: #if the value of the first elem of last element in ans is same as x[0]
ans[-1][1]+=x[1]
ans[-1][2]+=x[2]
else:
ans.append(x)
else:ans.append(x)
....:
In [28]: ans
Out[28]: [['a', 30, 120], ['b', 10, 20]]
を使用してリストをソートせずにdefaultdict()
:
In [69]: dic=defaultdict(list)
In [70]: for x in lis:
dic[x[0]].append(x[1:])
....:
In [71]: dic
Out[71]: defaultdict(<type 'list'>, {'a': [[10, 20], [20, 100]], 'b': [[10, 20]]})
In [72]: [[k]+map(sum,zip(*i)) for k,i in dic.items()]
Out[72]: [['a', 30, 120], ['b', 10, 20]]
dict
およびを使用する別のアプローチmap
:
>>> x = [['a', 10, 20], ['b', 10, 20], ['a', 20, 100]]
>>> d = {}
>>> from operator import add
>>> for k, v1, v2 in x:
d[k] = map(add, d.get(k, [0, 0]), [v1, v2])
>>> d
{'a': [30, 120], 'b': [10, 20]}
数百万を超える要素を含む膨大なデータの回答コードを使用します。この方法でリスト要素を減らしたいのですが。
このような場合、データを繰り返し処理するときに、データを並べ替えたり、完全なコピーを作成したりすることはおそらく望ましくありません。
次の解決策はどちらも行いません。また、任意の長さのサブリストを処理できます(すべての長さが同じである限り)。
def add(d, l):
k = l[0] # extract the key
p = d.get(k, None) # see if we already have a partial sum for this key
if p:
d[k] = [x+y for x,y in zip(p, l[1:])] # add to the previous sum
else:
d[k] = l[1:] # create a new sum
return d
x = [['a', 10, 20], ['b', 10, 20], ['a', 20, 100]]
result = [[k] + v for k,v in reduce(add, x, {}).items()]
print(result)
または、
import collections, operator
x = [['a', 10, 20], ['b', 10, 20], ['a', 20, 100]]
d = collections.defaultdict(lambda:[0] * (len(x[0]) - 1))
for el in x:
d[el[0]] = map(operator.add, d[el[0]], el[1:])
result = [[k] + v for k,v in d.items()]
print(result)
これは最初のバージョンとまったく同じように機能しますがdefaultdict
、明示的な反復を使用します。