我已经用谷歌搜索了这个并得到了零散/矛盾的意见 -在 Ruby/Rails 中对数组执行 amap
和执行 a之间实际上有什么区别吗?collect
文档似乎没有任何建议,但方法或性能可能存在差异?
没有区别,实际上map
在 C 中实现为rb_ary_collect
and enum_collect
(例如,数组和任何其他枚举之间存在差异,但andmap
之间没有区别)。map
collect
为什么两者都map
存在collect
于 Ruby 中?该map
函数有许多不同语言的命名约定。维基百科提供了一个概述:
map 函数起源于函数式编程语言,但今天在许多过程、面向对象和多范式语言中也得到支持(或可能被定义):在 C++ 的标准模板库中,它
transform
在 C# (3.0) 中被称为LINQ 库,它作为扩展方法提供,称为Select
. Map 也是 Perl、Python 和 Ruby 等高级语言中常用的操作;该操作map
以所有这三种语言调用。Ruby 中也提供了 map的collect
别名(来自 Smalltalk) [强调我的]。Common Lisp 提供了一系列类似地图的函数;与此处描述的行为相对应的行为称为mapcar
(-car 指示使用 CAR 操作进行访问)。
Ruby 为来自 Smalltalk 世界的程序员提供了一个别名,让他们有宾至如归的感觉。
为什么数组和枚举有不同的实现?枚举是一种通用的迭代结构,这意味着 Ruby 无法预测下一个元素是什么(您可以定义无限枚举,参见Prime示例)。因此它必须调用一个函数来获取每个连续的元素(通常这将是each
方法)。
数组是最常见的集合,因此优化它们的性能是合理的。由于 Ruby 非常了解数组的工作原理,因此它不必调用each
,而只能使用简单的指针操作,这明显更快。
zip
许多 Array 方法(例如or )也存在类似的优化count
。
我被告知他们是一样的。
实际上,它们记录在 ruby-doc.org 下的同一个地方:
http://www.ruby-doc.org/core/classes/Array.html#M000249
- ary.collect {|项目| 块 } → new_ary
- ary.map {|项目| 块 } → 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
andcollect!
方法是 and 的别名,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;
}
#collect
实际上是#map
. 这意味着这两种方法可以互换使用,并产生相同的行为。