Elementweise Hinzufügung von 2 Listen?

244

Ich habe jetzt:

list1 = [1, 2, 3]
list2 = [4, 5, 6]

Ich möchte haben:

[1, 2, 3]
 +  +  +
[4, 5, 6]
|| || ||
[5, 7, 9]

Einfach eine elementweise Hinzufügung von zwei Listen.

Ich kann die beiden Listen sicherlich wiederholen, aber das möchte ich nicht.

Was ist der pythonischste Weg, dies zu tun?

Sibbs Glücksspiel
quelle
Mögliches Duplikat des Hinzufügens
Nikos Alexandris

Antworten:

364

Verwendung mapmit operator.add:

>>> from operator import add
>>> list( map(add, list1, list2) )
[5, 7, 9]

oder zipmit einem Listenverständnis:

>>> [sum(x) for x in zip(list1, list2)]
[5, 7, 9]

Zeitvergleiche:

>>> list2 = [4, 5, 6]*10**5
>>> list1 = [1, 2, 3]*10**5
>>> %timeit from operator import add;map(add, list1, list2)
10 loops, best of 3: 44.6 ms per loop
>>> %timeit from itertools import izip; [a + b for a, b in izip(list1, list2)]
10 loops, best of 3: 71 ms per loop
>>> %timeit [a + b for a, b in zip(list1, list2)]
10 loops, best of 3: 112 ms per loop
>>> %timeit from itertools import izip;[sum(x) for x in izip(list1, list2)]
1 loops, best of 3: 139 ms per loop
>>> %timeit [sum(x) for x in zip(list1, list2)]
1 loops, best of 3: 177 ms per loop
Ashwini Chaudhary
quelle
10
Wenn Sie diese riesigen Arrays verwenden, sollten Sie sich wahrscheinlich die numpy-Lösung von @BasSwinckels ansehen.
Henry Gomersall
1
Welche Python-Version haben Sie für diese Timings verwendet?
Arshajii
9
NB - In Python3 gibt map () eher ein iterierbares Ding als eine Liste zurück. Wenn Sie eine aktuelle Liste benötigen, ist die erste Antwort Liste (Karte (hinzufügen, Liste1, Liste2))
FLHerne
Das von @FLHerne mit festgestellte Python3-Problem wird mit der mapZeit immer wichtiger. Python 2 wird in weniger als 3 Jahren die offizielle Unterstützung verlieren.
Nealmcb
1
Es gibt viele Male, in denen die Python-Syntax wirklich elegant und einfach ist, aber leider gehört dies nicht dazu. Und für eine so einfache Aufgabe ist es schade ... Warum sollten sie die Listen mit "+" verketten, wenn es bereits die Methode .extend () gibt?
Nic Scozzaro
105

Die anderen gaben Beispiele, wie dies in reinem Python gemacht wird. Wenn Sie dies mit Arrays mit 100.000 Elementen tun möchten, sollten Sie numpy verwenden:

In [1]: import numpy as np
In [2]: vector1 = np.array([1, 2, 3])
In [3]: vector2 = np.array([4, 5, 6])

Das elementweise Hinzufügen ist jetzt so trivial wie

In [4]: sum_vector = vector1 + vector2
In [5]: print sum_vector
[5 7 9]

genau wie in Matlab.

Timing zum Vergleich mit Ashwinis schnellster Version:

In [16]: from operator import add
In [17]: n = 10**5
In [18]: vector2 = np.tile([4,5,6], n)
In [19]: vector1 = np.tile([1,2,3], n)
In [20]: list1 = [1,2,3]*n
In [21]: list2 = [4,5,6]*n
In [22]: timeit map(add, list1, list2)
10 loops, best of 3: 26.9 ms per loop

In [23]: timeit vector1 + vector2
1000 loops, best of 3: 1.06 ms per loop

Das ist also ein Faktor 25 schneller! Aber verwenden Sie, was zu Ihrer Situation passt. Für ein einfaches Programm möchten Sie wahrscheinlich nicht numpy installieren, verwenden Sie also Standard-Python (und ich finde Henrys Version die pythonischste). Wenn Sie ernsthafte Zahlen knirschen, lassen numpySie das schwere Heben tun. Für die Geschwindigkeitsfreaks: Es scheint, dass die Numpy-Lösung von Anfang an schneller ist n = 8.

Bas Swinckels
quelle
59
[a + b for a, b in zip(list1, list2)]
Henry Gomersall
quelle
4
@deltab Die akzeptierte Antwort ist schneller und enthält diese Antwort (informativer)
Sibbs Gambling
2
@ perfectm1ng obwohl ich Ihren Punkt verstehe (und ihn kein bisschen missbillige), dachte ich nur, dass es sich lohnt, darauf hinzuweisen, dass ich immer entweder die von mir vorgestellte Lösung verwenden würde (was vorausgesetzt, dass keine Importe erforderlich sind, ist wohl auch die einfachste als wohl pythonischer) oder wo Geschwindigkeit zählt, die Antwort von Bas Swinckel , die überwiegend die richtige Option ist, wenn Geschwindigkeit wichtig ist.
Henry Gomersall
Ja. Danke für die Meinung. Aber im Wesentlichen [sum(x) for x in zip(list1, list2)]ist es dasselbe wie Ihre Antwort, nicht wahr? :)
Sibbs Gambling
4
@ perfectm1ng Mehr oder weniger (obwohl es nach meinem mit einer Bearbeitung hinzugefügt wurde :). Persönlich bevorzuge ich die A + B-Notation mit explizitem Tupel-Auspacken, um Lesbarkeit und Python zu gewährleisten.
Henry Gomersall
12

Wie von anderen beschrieben, verwendet eine schnelle und auch platzsparende Lösung numpy (np) mit seiner integrierten Vektormanipulationsfunktion:

1. Mit Numpy

x = np.array([1,2,3])
y = np.array([2,3,4])
print x+y

2. Mit Einbauten

2.1 Lambda

list1=[1, 2, 3]
list2=[4, 5, 6]
print map(lambda x,y:x+y, list1, list2)

Beachten Sie, dass map () mehrere Argumente unterstützt.

2.2 Zip- und Listenverständnis

list1=[1, 2, 3]
list2=[4, 5, 6]
print [x + y for x, y in zip(list1, list2)]
MasterControlProgram
quelle
1
+1 für den Lambda-Ansatz. Es ist eine Schande, dass diese Lösung mit anderen Lösungen kombiniert wird, die an anderer Stelle dupliziert werden.
LondonRob
10

numpyMeiner Meinung nach ist es einfacher zu bedienen :

import numpy as np
list1=[1,2,3]
list2=[4,5,6]
np.add(list1,list2)

Ergebnisse:

Terminalausführung

Ausführliche Informationen zu den Parametern finden Sie hier: numpy.add

Ludwig Zhou
quelle
6

Vielleicht sollte "der pythonischste Weg" die Behandlung des Falls beinhalten, in dem Liste1 und Liste2 nicht dieselbe Größe haben. Wenn Sie einige dieser Methoden anwenden, erhalten Sie leise eine Antwort. Der Numpy-Ansatz informiert Sie höchstwahrscheinlich über einen ValueError.

Beispiel:

import numpy as np
>>> list1 = [ 1, 2 ]
>>> list2 = [ 1, 2, 3]
>>> list3 = [ 1 ]
>>> [a + b for a, b in zip(list1, list2)]
[2, 4]
>>> [a + b for a, b in zip(list1, list3)]
[2]
>>> a = np.array (list1)
>>> b = np.array (list2)
>>> a+b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (2) (3)

Welches Ergebnis könnten Sie wünschen, wenn dies in einer Funktion in Ihrem Problem wäre?

Fred Mitchell
quelle
in diesem zip_longestfall sollte man auf jeden fall von itertools mit einem fillvaluevon schauen 0.
Ma0 vor
6

Das ist einfach mit numpy.add()

import numpy

list1 = numpy.array([1, 2, 3])
list2 = numpy.array([4, 5, 6])
result = numpy.add(list1, list2) # result receive element-wise addition of list1 and list2
print(result)
array([5, 7, 9])

Siehe Dokument hier

Wenn Sie eine Python-Liste erhalten möchten:

result.tolist()
Eduardo Basílio
quelle
5

Dies funktioniert für 2 oder mehr Listen. Durchlaufen der Listenliste, aber Verwenden der numpy-Addition, um die Elemente jeder Liste zu behandeln

import numpy as np
list1=[1, 2, 3]
list2=[4, 5, 6]

lists = [list1, list2]
list_sum = np.zeros(len(list1))
for i in lists:
   list_sum += i
list_sum = list_sum.tolist()    

[5.0, 7.0, 9.0]
Präsenz
quelle
5

Vielleicht ist dies pythonisch und etwas nützlich, wenn Sie eine unbekannte Anzahl von Listen haben und nichts importieren.

Solange die Listen gleich lang sind, können Sie die folgende Funktion verwenden.

Hier akzeptiert * args eine variable Anzahl von Listenargumenten (summiert jedoch jeweils nur die gleiche Anzahl von Elementen).

Das * wird in der zurückgegebenen Liste erneut verwendet, um die Elemente in jeder der Listen zu entpacken.

def sum_lists(*args):
    return list(map(sum, zip(*args)))

a = [1,2,3]
b = [1,2,3]  

sum_lists(a,b)

Ausgabe:

[2, 4, 6]

Oder mit 3 Listen

sum_lists([5,5,5,5,5], [10,10,10,10,10], [4,4,4,4,4])

Ausgabe:

[19, 19, 19, 19, 19]
Flügel
quelle
3

Karte mit Lambda-Funktion verwenden:

>>> map(lambda x, y: x + y, list1, list2)
[5, 7, 9]
Peater
quelle
3

Ich habe es nicht geplant, aber ich vermute, dass dies ziemlich schnell gehen würde:

import numpy as np
list1=[1, 2, 3]
list2=[4, 5, 6]

list_sum = (np.add(list1, list2)).tolist()

[5, 7, 9]
Präsenz
quelle
3

Wenn Sie Listen unterschiedlicher Größe bearbeiten müssen, machen Sie sich keine Sorgen! Das wunderbare itertools- Modul hat Sie behandelt:

>>> from itertools import zip_longest
>>> list1 = [1,2,1]
>>> list2 = [2,1,2,3]
>>> [sum(x) for x in zip_longest(list1, list2, fillvalue=0)]
[3, 3, 3, 3]
>>>

In Python 2 zip_longestheißt izip_longest.

Siehe auch diese relevante Antwort und Kommentar zu einer anderen Frage .

jjst
quelle
3
[list1[i] + list2[i] for i in range(len(list1))]
wgr
quelle
1
Mehr Python wäre[a + b for (a, b) in zip(list1, list2)]
Rayryeng
2

Die eigentliche Frage möchte zwar nicht über die Liste iterieren, um das Ergebnis zu generieren, aber alle vorgeschlagenen Lösungen tun genau das unter der Haube!

So aktualisieren Sie: Sie können nicht zwei Vektoren hinzufügen, ohne alle Vektorelemente zu untersuchen. Die algorithmische Komplexität der meisten dieser Lösungen ist also Big-O (n). Wobei n die Dimension des Vektors ist.

Aus algorithmischer Sicht ist die Verwendung einer for-Schleife zum iterativen Generieren der resultierenden Liste logisch und auch pythonisch. Darüber hinaus hat diese Methode jedoch nicht den Aufwand, zusätzliche Bibliotheken aufzurufen oder zu importieren.

# Assumption: The lists are of equal length.
resultList = [list1[i] + list2[i] for i in range(len(list1))]

Die hier gezeigten / diskutierten Zeitpunkte sind system- und implementierungsabhängig und können keine zuverlässige Maßnahme zur Messung der Effizienz des Vorgangs sein. In jedem Fall ist die große O-Komplexität der Vektoradditionsoperation linear, was O (n) bedeutet.

Ehsan
quelle
1
a_list = []
b_list = []
for i in range(1,100):
    a_list.append(random.randint(1,100))

for i in range(1,100):
    a_list.append(random.randint(101,200))
[sum(x) for x in zip(a_list , b_list )]
DSBLR
quelle