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


426

我已经对此进行了Google搜索,并得到了斑驳的/矛盾的意见- 在Ruby / Rails中对数组执行a map和a 之间实际上有什么区别collect吗?

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


5
mapCode Golf的首选。
卡里·斯沃夫兰

1
解释一下为什么map在CodeGolf上会首选它,这可能并非对所有人都显而易见:这仅仅是因为它collect比的长四个字符map,但功能相同。
Jochem Schulenklopper '16

2
只是扮演恶魔的拥护者,我个人觉得它collect更具可读性和自然性-与“映射”记录并对它们执行X相比,“收集”记录并对它们执行X的想法对我来说更自然。
sscirrus

Answers:


479

没什么区别,实际上map是在C中以rb_ary_collect和实现的enum_collect(例如map,数组和任何其他枚举之间都有区别,而map和之间没有区别collect)。


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

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

Ruby为Smalltalk世界的程序员提供了别名,使他们感到宾至如归。


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

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

对于许多类似zip或的Array方法,也存在类似的优化方法count


13
@Mark Reed,但是后来,来自SmallTalk的程序员会因为具有两个不同的功能而感到困惑,因为这两个功能只是别名。它会引起类似上面的OP之类的问题。
2013年

10
@SasQ我不同意-如果只有一个名字,总的来说会更好。但是Ruby中还有很多其他别名,别名的一个功能是在collectdetectinjectrejectselect(否则称为mapfindreducereject(没有别名) )和find_all)。
马克·里德

4
确实。显然,Ruby在更多场合使用别名/同义词。例如,在阵列中元件的数量可以与被检索countlengthsize。不同的词对数组的相同的属性,而是由这一点,红宝石让你挑选最合适的词为您的代码:你想要的号码项目你正在收集中,数组,或当前大小的结构。从本质上讲,它们都是相同的,但是选择正确的单词可能会使您的代码更易于阅读,这是该语言的一个不错的特性。
Jochem Schulenklopper '16

51

有人告诉我他们是一样的。

实际上,它们被记录在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

对于自身的每个元素,调用都会阻塞一次。创建一个包含该块返回的值的新数组。另请参见Enumerable#collect。
如果没有给出块,则返回一个枚举数。

a = [ "a", "b", "c", "d" ]
a.collect {|x| x + "!" }   #=> ["a!", "b!", "c!", "d!"]
a                          #=> ["a", "b", "c", "d"]


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

我得到的结果是:

                   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) 

也许别名不是免费的?


1
我不确定这些差异是否显着。在重新运行时,我得到了不同的速度结果(即使您的哈希收集看起来较慢,您的数组收集似乎也较快)
murb

10

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

Array.instance_method(:map) == Array.instance_method(:collect)
 => true

7

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


4
我希望文档明确声明它们是别名。目前,它们只是相互引用,并且两者的描述略有不同。
克里斯·布鲁姆
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.