Разница между map и collect в Ruby?
я погуглил это и получил отрывочные / противоречивые мнения - есть ли на самом деле какая-то разница между выполнением map
и collect
на массиве в Ruby / Rails?
на docs не похоже, чтобы предложить какие-либо, но, возможно, есть различия в методе или производительности?
5 ответов
нет никакой разницы, на самом деле map
реализовано в C как rb_ary_collect
и enum_collect
(напр. есть разница между map
на массиве и на любом другом перечислении, но никакой разницы между map
и collect
).
почему map
и collect
существуют в Ruby? на map
функция имеет много соглашений об именах на разных языках. Википедия предоставляет обзор:
функции карте возникший в функциональных языках программирования, но сегодня поддерживается (или может быть определен) во многих процедурных, объектно-ориентированных и многопарадигмальных языках: в стандартной библиотеке шаблонов C++он называется
transform
, в библиотеке LINQ C# (3.0), она предоставляется как метод расширения под названиемSelect
. Map также часто используется в языках высокого уровня, таких как Perl, Python и Ruby; операция называетсяmap
на всех трех языках. Acollect
псевдоним карта также предоставляется в Ruby (от Smalltalk) [выделено мной]. Common Lisp предоставляет семейство картоподобных функций; та, которая соответствует описанному здесь поведению, называетсяmapcar
(- автомобиль показывая доступ используя деятельность автомобиля).
Ruby предоставляет псевдоним для программистов из мира Smalltalk, чтобы чувствовать себя как дома.
почему существует другая реализация для массивов и перечислений? enum является обобщенной итерационная структура, что означает, что Ruby не может предсказать, каким может быть следующий элемент (вы можете определить бесконечные перечисления, см. премьер - для примера). Поэтому он должен вызывать функцию для получения каждого последующего элемента (обычно это будет each
метод).
массивы являются наиболее распространенной коллекцией, поэтому разумно оптимизировать их производительность. Поскольку Ruby много знает о том, как работают массивы, ему не нужно вызывать each
но только используйте простой манипуляции указатель что значительно быстрее.
подобные оптимизации существуют для ряда методов массива, таких как zip
или count
.
Я сказал они одинаковы.
на самом деле они документированы в том же месте под ruby-doc.org:
http://www.ruby-doc.org/core/classes/Array.html#M000249
- Варь.соберите {/item / block } → new_ary
- Варь.карта {/item / block } → new_ary
- Варь.соберите → an_enumerator
- Варь.карта → an_enumerator
вызывает блок один раз для каждого элемента самостоятельно. Создает новый массив, содержащий значения, возвращаемые блоком. См. также Enumerable#collect.
Если блок не задан, вместо него возвращается перечислитель.a = [ "a", "b", "c", "d" ] a.collect {|x| x + "!" } #=> ["a!", "b!", "c!", "d!"] a #=> ["a", "b", "c", "d"]
Я сделал тест, чтобы попытаться ответить на этот вопрос, а затем нашел этот пост, поэтому вот мои выводы (которые немного отличаются от других ответов)
вот контрольный код:
require 'benchmark'
h = { abc: 'hello', 'another_key' => 123, 4567 => 'third' }
a = 1..10
many = 500_000
Benchmark.bm do |b|
GC.start
b.report("hash keys collect") do
many.times do
h.keys.collect(&:to_s)
end
end
GC.start
b.report("hash keys map") do
many.times do
h.keys.map(&:to_s)
end
end
GC.start
b.report("array collect") do
many.times do
a.collect(&:to_s)
end
end
GC.start
b.report("array map") do
many.times do
a.map(&:to_s)
end
end
end
и результаты, которые я получил, были:
user system total real
hash keys collect 0.540000 0.000000 0.540000 ( 0.570994)
hash keys map 0.500000 0.010000 0.510000 ( 0.517126)
array collect 1.670000 0.020000 1.690000 ( 1.731233)
array map 1.680000 0.020000 1.700000 ( 1.744398)
возможно, псевдоним не бесплатно?
Ruby псевдонимы метода Array#map to Array#collect; они могут использоваться взаимозаменяемо. (Руби Монк)
другими словами, тот же исходный код :
static VALUE
rb_ary_collect(VALUE ary)
{
long i;
VALUE collect;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
collect = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i)));
}
return collect;
}
на collect
и collect!
методы являются псевдонимами для map
и map!
, поэтому их можно использовать взаимозаменяемо. Вот простой способ подтвердить это:
Array.instance_method(:map) == Array.instance_method(:collect)
=> true