Ruby中的map和collect之间的区别?

ssc*_*rus 414 ruby arrays map collect

我用谷歌搜索了这个并得到了不完整/矛盾的观点 - 在Ruby/Rails中对一个数组做一个map和做一个实际上有什么区别collect吗?

这些文档似乎没有任何暗示,但是方法或性能可能存在差异吗?

Jak*_*mpl 464

没有区别,实际上map是用C实现为rb_ary_collectenum_collect(例如,之间是有区别map的阵列上,并在任何其他枚举,但是没有区别mapcollect).


为什么都mapcollectRuby的存在吗?map函数具有许多不同语言的命名约定.维基百科提供了一个概述:

map函数起源于函数式编程语言,但现在支持(或可能定义)许多过程,面向对象和多范式语言:在C++的标准模板库中,它被称为transformC#(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或的许多数组方法存在类似的优化count.

  • @Mark Reed但是,那些不是来自SmallTalk的程序员会因为两个不同的功能而变得混乱.它导致像上面的OP一样的问题. (11认同)
  • @SasQ我不反对 - 我认为如果只有一个名字那么整体会更好.但是Ruby中还有很多别名,而别名的一个特点就是操作中有一个很好的命名并行***,*detect*,*inject*,*reject*和*select*(也称为*)*map*,*find*,*reduce*,*reject*(无别名)和*find_all*). (9认同)
  • 确实.显然,Ruby在更多场合使用别名/同义词.例如,可以使用`count`,`length`或`size`检索数组中的元素数.对于数组的相同属性,不同的单词,但通过这个,Ruby使您能够为您的代码选择最合适的单词:您是否想要收集的项目的_number_,数组的_length_或当前的_size_ of结构.从本质上讲,它们都是一样的,但选择正确的单词可能会使您的代码更容易阅读,这是该语言的一个很好的属性. (3认同)

Osc*_*Ryz 50

我被告知他们是一样的.

实际上,他们在ruby-doc.org下的同一个地方被记录:

http://www.ruby-doc.org/core/classes/Array.html#M000249

  • ary.collect {| item | 阻止}→new_ary
  • ary.map {| item | 阻止}→new_ary
  • ary.collect→an_enumerator
  • ary.map→an_enumerator

为self的每个元素调用一次block.创建一个包含块返回的值的新数组.另见Enumerable#collect.
如果没有给出块,则返回枚举器.

a = [ "a", "b", "c", "d" ]
a.collect {|x| x + "!" }   #=> ["a!", "b!", "c!", "d!"]
a                          #=> ["a", "b", "c", "d"]
Run Code Online (Sandbox Code Playgroud)

  • 只是要彻底:[http://www.ruby-doc.org/core/classes/Enumerable.html#method-i-map](http://www.ruby-doc.org/core/classes/Enumerable .html#method-i-map) (2认同)

kte*_*tec 13

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

这是基准代码:

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
Run Code Online (Sandbox Code Playgroud)

我得到的结果是:

                   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) 
Run Code Online (Sandbox Code Playgroud)

也许别名不是免费的?

  • 我不确定这些差异是否显着。重新运行时,我得到不同的速度结果(即使你的哈希收集看起来更慢,你的数组收集看起来更快) (2认同)

jet*_*ton 7

Ruby将方法Array#map别名为Array#collect; 它们可以互换使用.(Ruby Monk)

换句话说,相同的源代码:

               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;
}
Run Code Online (Sandbox Code Playgroud)

http://ruby-doc.org/core-2.2.0/Array.html#method-i-map

  • 我希望文档明确说明它们是别名.目前他们只是互相引用,两者的描述略有不同. (3认同)

Bru*_*cca 6

collectcollect!方法别名mapmap!,所以它们可以互换使用。这是确认的简单方法:

Array.instance_method(:map) == Array.instance_method(:collect)
 => true
Run Code Online (Sandbox Code Playgroud)