我在谷歌上搜索了一下,得到了不一致/矛盾的意见——在Ruby/Rails中做一个映射和做一个数组的收集之间真的有什么区别吗?
文档似乎没有提出任何建议,但在方法或性能上是否存在差异?
我在谷歌上搜索了一下,得到了不一致/矛盾的意见——在Ruby/Rails中做一个映射和做一个数组的收集之间真的有什么区别吗?
文档似乎没有提出任何建议,但在方法或性能上是否存在差异?
有人告诉我他们是一样的。
实际上,它们在ruy-doc.org的同一个地方都有记录:
http://www.ruby-doc.org/core/classes/Array.html#M000249
必要。收集{|item| block}→new_ary 必要。映射{|item| block}→new_ary 必要。Collect→an_enumerator 必要。Map→an_enumerator 为self的每个元素调用一次block。 创建一个包含块返回值的新数组。 参见Enumerable#collect。 如果没有给出块,则返回枚举数。 A = [" A ", "b", "c", "d"] A.collect {|x| x + "!"} #=> ["a!", "b!", "c!", "d! "”) 一个 #=> [" a”、“b”、“c”,“d”)
没有区别,事实上map在C中实现为rb_ary_collect和enum_collect(例如。map在数组和其他enum上有区别,但map和collect没有区别)。
为什么在Ruby中同时存在map和collection ?map函数在不同的语言中有许多命名约定。维基百科提供了一个概述:
The map function originated in functional programming languages but is today supported (or may be defined) in many procedural, object oriented, and multi-paradigm languages as well: In C++'s Standard Template Library, it is called transform, in C# (3.0)'s LINQ library, it is provided as an extension method called Select. Map is also a frequently used operation in high level languages such as Perl, Python and Ruby; the operation is called map in all three of these languages. A collect alias for map is also provided in Ruby (from Smalltalk) [emphasis mine]. Common Lisp provides a family of map-like functions; the one corresponding to the behavior described here is called mapcar (-car indicating access using the CAR operation).
Ruby为Smalltalk世界的程序员提供了一个别名,让他们感觉更自在。
为什么数组和枚举有不同的实现?枚举是一种广义迭代结构,这意味着Ruby无法预测下一个元素是什么(您可以定义无限枚举,参见Prime的例子)。因此,它必须调用一个函数来获取每个连续的元素(通常是each方法)。
数组是最常见的集合,因此优化它们的性能是合理的。由于Ruby非常了解数组的工作方式,因此它不需要调用每个数组,而是可以使用简单的指针操作,这要快得多。
许多Array方法(如zip或count)也存在类似的优化。
Ruby将方法array# map别名为array# collect;它们可以互换使用。(Ruby和尚)
换句话说,相同的源代码:
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
我做了一个基准测试来尝试回答这个问题,然后找到了这篇文章,所以这里是我的发现(与其他答案略有不同)
下面是基准代码:
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)
也许别名不是免费的?
收集和收集!方法是映射和映射的别名!,所以它们可以互换使用。下面是一个简单的确认方法:
Array.instance_method(:map) == Array.instance_method(:collect)
=> true