Подтвердить что ты не робот

Когда следует использовать карту вместо цикла For?

Это относится к следующему: (в коде Python)

for i in object:
     doSomething(i)

против

map(doSomething, object)

Оба легко понять и короткие, но есть ли разница в скорости? Теперь, если doSomething имеет возвращаемое значение, которое нам нужно было проверить, оно будет возвращено как список из карты, а в цикле for мы могли бы либо создать наш собственный список, либо проверить по одному.

for i in object:
     returnValue = doSomething(i)
     doSomethingWithReturnValue(returnValue)

против

returnValue = map(doSomething, object)
map(doSomethingWithReturnValue, returnValue)

Теперь я чувствую, что они немного расходятся. Две функции doSomethingWithReturnValue могут отличаться в зависимости от того, проверяете ли они их на ходу, когда мы проходим через цикл или если проверка их всех сразу в конце дает разные результаты. Также кажется, что цикл for всегда будет работать, возможно, медленнее, когда карта будет работать только в определенных сценариях. Конечно, мы могли бы сделать изгибы, чтобы сделать любую работу, но все дело в том, чтобы избежать этого типа работы.

То, что я ищу, - это сценарий, в котором функция сопоставления по-настоящему сияет по сравнению с хорошо выполненной для цикла производительности, удобочитаемости, ремонтопригодности или скорости реализации. Если ответ действительно не имеет большого значения, я бы хотел знать, когда на практике люди используют тот или иной, или если он действительно полностью произволен и устанавливается стандартами кодирования в зависимости от вашего учреждения.

Спасибо!

4b9b3361

Ответ 1

map полезно, когда вы хотите применить функцию к каждому элементу итерабельного и вернуть список результатов. Это проще и кратче, чем использование цикла for и построение списка.

for часто читается для других ситуаций, а в lisp было много конструкций итераций, которые были написаны в основном с использованием макросов и карт. Таким образом, в случаях, когда map не подходит, используйте цикл for.

В теории, если бы у нас был компилятор/интерпретатор, который был достаточно умен, чтобы использовать несколько процессоров/процессоров, то map можно было бы реализовать быстрее, поскольку различные операции над каждым элементом могут выполняться параллельно. Однако я не думаю, что это так.

Ответ 2

Вы знакомы с модулем timeit? Ниже приведены некоторые тайминги. -s выполняет одноразовую настройку, а затем команда зацикливается и записывается самое лучшее время.

1> python -m timeit -s "L=[]; M=range(1000)" "for m in M: L.append(m*2)"
1000 loops, best of 3: 432 usec per loop

2> python -m timeit -s "M=range(1000);f=lambda x: x*2" "L=map(f,M)"
1000 loops, best of 3: 449 usec per loop

3> python -m timeit -s "M=range(1000);f=lambda x:x*2" "L=[f(m) for m in M]"
1000 loops, best of 3: 483 usec per loop

4> python -m timeit -s "L=[]; A=L.append; M=range(1000)" "for m in M: A(m*2)"
1000 loops, best of 3: 287 usec per loop    

5> python -m timeit -s "M=range(1000)" "L=[m*2 for m in M]"
1000 loops, best of 3: 174 usec per loop

Обратите внимание, что все они похожи, за исключением последних двух. Это вызовы функции (L.append или f (x)), которые сильно влияют на время. В # 4 поиск L.append выполняется один раз в настройке. В # 5 используется список comp без вызовов функций.

Ответ 3

просто используйте списки: они более питоничны. Они также имеют синтаксис, аналогичный выражению генератора, который позволяет легко переключаться с одного на другой. Вам не нужно ничего менять при преобразовании кода в py3k: map возвращает итерабельность в py3k, и вам нужно будет настроить свой код.

если вы не заботитесь о возвращаемых значениях, просто не называйте новый список, вам нужно использовать возвращаемые значения один раз в коде, который вы можете переключить на выражения генератора и единое понимание списка в конце.

Ответ 4

EDIT: я не понял, что map равно itertools.imap после python 3.0. Таким образом, вывод здесь может быть неправильным. Я перезапущу тест на python 2.6 завтра и опубликую результат.

Если doSomething очень "крошечный", map может быть намного быстрее, чем цикл for или понимание списка:

# Python 3.1.1 (r311:74483, Aug 17 2009, 17:02:12) [MSC v.1500 32 bit (Intel)] on win32

from timeit import timeit

do = lambda i: i+1

def _for():
  for i in range(1000):
    do(i)

def _map():
  map(do, range(1000))

def _list():
  [do(i) for i in range(1000)]

timeit(_for, number=10000)  # 2.5515936921388516
timeit(_map, number=10000)  # 0.010167432629884843
timeit(_list, number=10000) # 3.090125159839033

Это связано с тем, что map написан на C, а for цикл и выполнение списка выполняются на виртуальной машине python.