没有区别,实际上 map
在 C 中实现为 rb_ary_collect
和 enum_collect
(例如,数组上的 map
和任何其他枚举之间存在差异,但 map
和 { 6})。
为什么 Ruby 中同时存在 map
和 collect
? map
函数在不同语言中有许多命名约定。 Wikipedia provides an overview:
map 函数起源于函数式编程语言,但如今在许多过程、面向对象和多范式语言中也得到支持(或可能被定义):在 C++ 的标准模板库中,它在 C# (3.0) 中称为转换s LINQ 库,它作为一个名为 Select 的扩展方法提供。 Map 也是 Perl、Python 和 Ruby 等高级语言中常用的操作;该操作在所有这三种语言中都称为 map。 Ruby(来自 Smalltalk)[强调我的] 中还提供了 map 的 collect 别名。 Common Lisp 提供了一系列类似地图的函数;与此处描述的行为相对应的一种称为 mapcar(-car 表示使用 CAR 操作进行访问)。
Ruby 为来自 Smalltalk 世界的程序员提供了一个别名,让他们有宾至如归的感觉。
为什么数组和枚举有不同的实现方式?枚举是一种广义的迭代结构,这意味着 Ruby 无法预测下一个元素可能是什么(可以定义无限枚举,请参见 Prime 示例)。因此它必须调用一个函数来获取每个连续的元素(通常这将是 each
方法)。
数组是最常见的集合,因此优化它们的性能是合理的。由于 Ruby 非常了解数组的工作原理,因此它不必调用 each
,而只能使用简单的 pointer manipulation,这明显更快。
许多 Array 方法(如 zip
或 count
)存在类似的优化。
我被告知他们是一样的。
实际上,它们记录在 ruby-doc.org 下的同一个地方:
http://www.ruby-doc.org/core/classes/Array.html#M000249
ary.collect {|项目|块 } → new_ary ary.map {|item| block } → new_ary ary.collect → an_enumerator ary.map → an_enumerator 为 self 的每个元素调用一次块。创建一个包含块返回值的新数组。另请参见 Enumerable#collect。如果没有给出块,则返回一个枚举器。 a = [ "a", "b", "c", "d" ] a.collect {|x| x + "!" } #=> ["a!", "b!", "c!", "d!"] a #=> ["a", "b", "c", "d"]
collect
和 collect!
方法是 map
和 map!
的别名,因此它们可以互换使用。这里有一个简单的方法来确认:
Array.instance_method(:map) == Array.instance_method(:collect)
=> true
我做了一个基准测试来尝试回答这个问题,然后找到了这篇文章,所以这是我的发现(与其他答案略有不同)
这是基准代码:
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 别名为 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;
}
http://ruby-doc.org/core-2.2.0/Array.html#method-i-map
#collect
实际上是 #map
的别名。这意味着这两种方法可以互换使用,并产生相同的行为。
count
、length
或size
检索数组中的元素数。数组的同一属性使用不同的词,但是通过这种方式,Ruby 可以让您为代码选择最合适的词:您想要收集的项目的 number 个,数组的长度,或结构的当前大小。本质上,它们都是相同的,但是选择正确的词可能会使您的代码更易于阅读,这是该语言的一个很好的属性。