448

我已经用谷歌搜索了这个并得到了零散/矛盾的意见 -在 Ruby/Rails 中对数组执行 amap和执行 a之间实际上有什么区别吗?collect

文档似乎没有任何建议,但方法或性能可能存在差异?

4

6 回答 6

508

没有区别,实际上map在 C 中实现为rb_ary_collectand enum_collect(例如,数组和任何其他枚举之间存在差异,但andmap之间没有区别)。mapcollect


为什么两者都map存在collect于 Ruby 中?map函数有许多不同语言的命名约定。维基百科提供了一个概述

map 函数起源于函数式编程语言,但今天在许多过程、面向对象和多范式语言中也得到支持(或可能被定义):在 C++ 的标准模板库中,它transform在 C# (3.0) 中被称为LINQ 库,它作为扩展方法提供,称为Select. Map 也是 Perl、Python 和 Ruby 等高级语言中常用的操作;该操作map以所有这三种语言调用。Ruby 中也提供了 mapcollect别名(来自 Smalltalk) [强调我的]。Common Lisp 提供了一系列类似地图的函数;与此处描述的行为相对应的行为称为mapcar(-car 指示使用 CAR 操作进行访问)。

Ruby 为来自 Smalltalk 世界的程序员提供了一个别名,让他们有宾至如归的感觉。


为什么数组和枚举有不同的实现?枚举是一种通用的迭代结构,这意味着 Ruby 无法预测下一个元素是什么(您可以定义无限枚举,参见Prime示例)。因此它必须调用一个函数来获取每个连续的元素(通常这将是each方法)。

数组是最常见的集合,因此优化它们的性能是合理的。由于 Ruby 非常了解数组的工作原理,因此它不必调用each,而只能使用简单的指针操作,这明显更快。

zip许多 Array 方法(例如or )也存在类似的优化count

于 2011-03-10T02:24:34.003 回答
54

我被告知他们是一样的。

实际上,它们记录在 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"]
于 2011-03-10T02:23:32.203 回答
15

collectandcollect!方法是 and 的别名,map因此map!它们可以互换使用。这里有一个简单的方法来确认:

Array.instance_method(:map) == Array.instance_method(:collect)
 => true
于 2018-10-01T20:05:57.577 回答
14

我做了一个基准测试来尝试回答这个问题,然后找到了这篇文章,所以这是我的发现(与其他答案略有不同)

这是基准代码:

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) 

也许别名不是免费的?

于 2016-01-01T00:52:28.757 回答
8

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

于 2015-02-27T02:25:02.380 回答
1

#collect实际上是#map. 这意味着这两种方法可以互换使用,并产生相同的行为。

于 2020-10-28T23:11:14.357 回答