Mamy listę:

import numpy as np


A=[(2, 2, 0), (1, 5, 0), (6, 8, 0), (2, 2, 2) ]

ax=np.asarray([row[0] for row in A])
ay=np.asarray([row[1] for row in A])
az=np.asarray([row[2] for row in A])

print (ax,ay,az)

Chciałbym porównać AX z AY i kiedy znajdę równe pary, gdzie AX == AY lubi (2, 2, 0) i (2, 2, 2), a następnie dodam parę, ale dodać wartości AZ. Tak więc w naszym przykładzie nowa lista poszukiwana byłaby:

B=[(2, 2, 2), (1, 5, 0), (6, 8, 0)]

Miło byłoby mieć jakiś kod, który byłby skuteczny z naprawdę ogromnymi listami.

1
CosmoSurreal 27 lipiec 2012, 15:05

2 odpowiedzi

Najlepsza odpowiedź

Słownik (lub kolekcje.Counter) jest szybszy, aby sprawdzić obecne elementy niż macierz numpy.

Więc jeśli zamówienie wyjściowe nie jest ważne:

from collections import Counter
c = Counter()
A = [(2, 2, 0), (1, 5, 0), (6, 8, 0), (2, 2, 2) ]
for a in A:
    c[a[:2]] += a[2]
B = [list(k) + [v] for k,v in c.iteritems()]

B jest teraz:

[[1, 5, 0],  [6, 8, 0], [2, 2, 2]]
2
eumiro 27 lipiec 2012, 11:16

Jeśli zamówienie nie jest ważne

from collections import defaultdict

dd = defaultdict(int)
for x, y, z in A:
    dd[(x,y)] += z
res = [k + (v,) for k, v in dd.iteritems()]
# [(1, 5, 0), (6, 8, 0), (2, 2, 2)]

Jeśli zamówienie jest ważne

from operator import itemgetter

d = {}
for idx, (x, y, z) in enumerate(A):
    pos, freq = d.get((x,y), (0,0))
    d[(x,y)] = min(pos, idx), freq + z

res = sorted((k + (v[1],) for k, v in d.iteritems()), key=itemgetter(1, 1))
# [(2, 2, 2), (1, 5, 0), (6, 8, 0)]
1
Jon Clements 27 lipiec 2012, 12:22