Нельзя ли все или большинство случаев `each` заменить на `map`?

Разница между Enumerable#each и Enumerable#map заключается в том, возвращает ли он приемник или сопоставленный результат. Возврат к получателю тривиален, и вам обычно не нужно продолжать цепочку методов после each, как each{...}.another_method (я, вероятно, не видел такого случая. Даже если вы хотите вернуться к получателю, вы можете сделать это с помощью tap). Поэтому я думаю, что все или большинство случаев, когда используется Enumerable#each, можно заменить на Enumerable#map. Я ошибся? Если я прав, какова цель each? map медленнее, чем each?

Изменить: я знаю, что each принято использовать, когда возвращаемое значение вас не интересует. Меня не интересует, существует ли такая практика, но меня интересует, имеет ли такая практика смысл кроме как с точки зрения условности.


person sawa    schedule 30.09.2012    source источник


Ответы (4)


Выбор между map или each должен определяться желаемым конечным результатом: новый массив или отсутствие нового массива. Результат map может быть огромным и/или глупым:

p ("aaaa".."zzzz").map{|word| puts word} #huge and useless array of nil's
person steenslag    schedule 30.09.2012
comment
Если он медленный, я понимаю, что не должен его использовать, но почему он глупый? Я совсем этого не понимаю. Ruby унаследовал от Lisp идею о том, что каждое вычисление возвращает значение. - person sawa; 30.09.2012
comment
Результатом этого map является массив с 456976 нулями (puts возвращает ноль). Он удаляется после создания. Использование each вообще не создало бы его, сэкономив память. (Код немного изменен) - person steenslag; 30.09.2012
comment
Это было то, что я спрашиваю. Имеет ли это значение с точки зрения производительности. - person sawa; 30.09.2012
comment
Это тоже семантика. Другой человек, читающий ваш код, скорее всего, спросит, почему вы решили использовать map и с какой целью вы его использовали, хотя на самом деле его не было. - person Andrew Marshall; 30.09.2012

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

Когда вы используете each, ваш код говорит: «Я делаю что-то для каждого элемента». Когда вы используете map, ваш код говорит: «Я создаю новый массив, преобразуя каждый элемент».

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

person Wayne Conrad    schedule 30.09.2012

Я согласен с тем, что вы сказали. Enumerable#each просто возвращает исходный объект, для которого он был вызван, в то время как Enumerable#map устанавливает текущий итерируемый элемент в возвращаемое значение блока, а затем возвращает новый объект с этими изменениями.

Поскольку Enumerable#each просто возвращает сам исходный объект, он может быть очень предпочтителен по сравнению с map, когда дело доходит до случаев, когда вам нужно просто перебирать или перемещаться по элементам.

На самом деле, Enumerable#each — это простой и универсальный способ выполнения традиционного итерации цикла for, и каждый из них гораздо предпочтительнее цикла for в Ruby.

person Mithun Sasidharan    schedule 30.09.2012
comment
Честно говоря, меня не интересует, как другие люди предпочитают один метод другому. Меня интересует, есть ли смысл в особом использовании each. - person sawa; 30.09.2012

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

Например, вам нужно получить новый массив с индексами в нем:

array.each.with_index.map { |index, element| [index, element] }

Или, например, вам просто нужно применить какой-либо метод ко всем элементам в массиве и вывести результат, не изменяя исходный массив:

m = 2.method(:+)

[1,2,3].each { |a| puts m.call(a) } #=> prints 3, 4, 5

И есть масса других примеров, когда разница между each и map является важным ключом при написании кода в функциональном стиле.

person megas    schedule 30.09.2012