: P Ты спускаешься в мельчайшие детали, и я рад, что ты спросил, как ты будешь мудрее к концу.
Не смотрите на это с точки зрения указателей, потому что Я думаю, это то, где вы запутались. Подумайте об этом скорее с точки зрения кучи (или просто «памяти», если хотите) и таблицы символов.
Давайте начнем с ввода первых нескольких строк вашего кода:
var a, b;
a = {}
b = a;
Вы сделали здесь один объект в куче и два символа в таблице символов. Это выглядит примерно так:
Таблица символов :
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400000 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
Куча :
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
.
Здесь интересны вещи: у объектов есть свои «таблички символов» (обычно это просто хеш-таблицы, но называть их таблицей символов можно сделать более ясным).
Теперь, после вашего следующего утверждения, у вас есть 3 вещи: таблица глобального символа, таблица символов <object val 1>
и куча.
Запустите следующую строку:
a['one'] = {}
И теперь все выглядит так:
Глобальная таблица символов :
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400000 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
<object val 1>
Таблица символов
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| one | 0x400004 |
+--------+-----------------+
Куча :
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
| 0x400004 | <object val 2> | <---we created a new object on the heap
+----------+-----------------+
.
Теперь вы выполнили следующий код:
a = a['one'];
Это, должно быть, кажется тривиальным изменением. Результат:
Таблица глобальных символов :
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400004 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
Символьная таблица <object val 1>
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| one | 0x400004 |
+--------+-----------------+
Куча :
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
| 0x400004 | <object val 2> |
+----------+-----------------+
.
Следуя ячейкам памяти в куче, мы, надеюсь, сделаем это ясно, почему вы получили результат, который вы сделали.
Теперь все становится еще интереснее, потому что теперь вы делаете:
a['two'] = 2;
Хорошо, давайте сделаем это шаг за шагом.
a
указывает на ячейку памяти 0x400004
, которая содержит <object val 2>
<object val 2>
- пустой объект, поэтому его таблица символов начинает пуст <object val 2>
. Если вы еще не устали смотреть на эти диаграммы, вы будете быть. Теперь все выглядит так:
Таблица глобальных символов :
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| a | 0x400004 |
+--------+-----------------+
| b | 0x400000 |
+--------+-----------------+
Символьная таблица <object val 1>
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| one | 0x400004 |
+--------+-----------------+
<object val 2>
Символьная таблица
+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
| two | 0x400008 |
+--------+-----------------+
Куча :
+----------+-----------------+
| Location | Value |
+----------+-----------------+
| 0x400000 | <object val 1> |
+----------+-----------------+
| 0x400004 | <object val 2> |
+----------+-----------------+
| 0x400008 | 2 (literal val) | <-- yes, even integers are stored on the heap
+----------+-----------------+ in JavaScript.
.
Если вы усердно занимаете время, чтобы следить за местоположениями памяти, вы увидите, что ваш браузер отобразил правильный вывод.
Используйте map
с operator.add
:
>>> from operator import add
>>> list( map(add, list1, list2) )
[5, 7, 9]
или zip
со списком понимание:
>>> [sum(x) for x in zip(list1, list2)]
[5, 7, 9]
>>> 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
Другие приводили примеры того, как это сделать в чистом питоне. Если вы хотите сделать это с помощью массивов с 100 000 элементами, вы должны использовать numpy:
In [1]: import numpy as np
In [2]: vector1 = np.array([1, 2, 3])
In [3]: vector2 = np.array([4, 5, 6])
Выполнение элементарного добавления теперь так же тривиально, как
In [4]: sum_vector = vector1 + vector2
In [5]: print sum_vector
[5 7 9]
так же, как в Matlab.
Сроки сравнения с самой быстрой версией Ashwini:
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
Итак, это на 25 раз быстрее! Но используйте то, что подходит вашей ситуации. Для простой программы вы, вероятно, не хотите устанавливать numpy, поэтому используйте стандартный python (и я нахожу версию Henry самой питонической). Если вы находитесь в серьезном количестве хрустов, пусть numpy
делает тяжелый подъем. Для скорости freaks: кажется, что решение numpy быстрее начинается с n = 8
.
Если вам нужно обрабатывать списки разных размеров, не беспокойтесь! Замечательный модуль itertools вы рассмотрели:
>>> 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]
>>>
В Python 2 zip_longest
называется izip_longest
.
См. также этот ответ и комментарий к другому вопросу .
Это просто с 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])
Если вы хотите получить список python:
result.tolist()
Хотя, фактический вопрос не хочет перебирать список для генерации результата, но все предлагаемые решения делают именно то, что находится под капотом!
Чтобы обновить: вы не можете добавить два вектора, не просматривая все векторные элементы. Таким образом, алгоритмическая сложность большинства этих решений - Big-O (n). Где n - размерность вектора.
Итак, с алгоритмической точки зрения использование цикла for для итеративного генерации результирующего списка является логическим и питоновым. Однако, кроме того, этот метод не имеет накладных расходов на вызов или импорт какой-либо дополнительной библиотеки.
# Assumption: The lists are of equal length.
resultList = [list1[i] + list2[i] for i in range(len(list1))]
Тайминги, которые показываются / обсуждаются здесь, зависят от системы и реализации и не могут быть надежной мерой для измерения эффективности работы. В любом случае большая сложность операции вектора сложения O является линейной, что означает O (n).
Возможно, «самый пифонический путь» должен включать обработку случая, когда list1 и list2 не имеют одинакового размера. Применение некоторых из этих методов позволит вам дать ответ. Метод numpy даст вам знать, скорее всего, с помощью ValueError.
Пример:
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)
Какой результат вы хотите, если бы это было в функции в вашей проблеме?
[a + b for a, b in zip(list1, list2)]
[sum(x) for x in zip(list1, list2)]
совпадает с вашим ответом, не так ли? :)
– Sibbs Gambling
11 September 2013 в 11:55
Я не приурочил его, но я подозреваю, что это будет довольно быстро:
import numpy as np
list1=[1, 2, 3]
list2=[4, 5, 6]
list_sum = (np.add(list1, list2)).tolist()
[5, 7, 9]
По моему мнению, проще использовать numpy
:
import numpy as np
list1=[1,2,3]
list2=[4,5,6]
np.add(list1,list2)
Результаты:
Подробный параметр информацию, проверьте здесь: numpy.add
Как описано другими, быстрое, а также эффективное решение пространства использует numpy (np) с его встроенной возможностью векторной манипуляции:
1. С Numpy
x = np.array([1,2,3])
y = np.array([2,3,4])
print x+y
2. С встроенными функциями
2.1 Lambda
list1=[1, 2, 3]
list2=[4, 5, 6]
print map(lambda x,y:x+y, list1, list2)
Обратите внимание, что map () поддерживает несколько аргументов.
2.2 zip и понимание списка
list1=[1, 2, 3]
list2=[4, 5, 6]
print [x + y for x, y in zip(list1, list2)]
Использовать карту с лямбда-функцией:
>>> map(lambda x, y: x + y, list1, list2)
[5, 7, 9]
[list1[i] + list2[i] for i in range(len(list1))]
map
, будет становиться все более важной с течением времени. Python 2 потеряет официальную поддержку менее чем за 3 года. – nealmcb 10 April 2017 в 00:29