ChatGPT解决这个技术问题 Extra ChatGPT

Ruby中地图和收集之间的区别?

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

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

Code Golf 首选 map
作为对为什么在 CodeGolf 中首选 map 的解释,这对所有人来说可能并不明显:只是因为 collectmap 长四个字符,但功能相同。
只是为了扮演魔鬼的拥护者,我个人认为 collect 更具可读性和自然性 - “收集”记录并对它们做 X 的想法对我来说比“映射”记录并对它们做 X 更自然。

J
Jakub Hampl

没有区别,实际上 map 在 C 中实现为 rb_ary_collectenum_collect(例如,数组上的 map 和任何其他枚举之间存在差异,但 map 和 { 6})。

为什么 Ruby 中同时存在 mapcollect map 函数在不同语言中有许多命名约定。 Wikipedia provides an overview

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

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

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

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

许多 Array 方法(如 zipcount)存在类似的优化。


@Mark Reed 但是,不是来自 SmallTalk 的程序员会因为有两个不同的函数而感到困惑,而这两个函数原来只是别名。它会引起类似上述 OP 的问题。
@SasQ 我不反对——我认为如果只有一个名字会更好。但是 Ruby 中还有很多其他别名,别名的一个特点是在收集、检测、注入、拒绝和选择(也称为 map、find、reduce、reject)操作之间有一个很好的命名平行(没有别名) 和 find_all)。
的确。显然,Ruby 在更多场合使用别名/同义词。例如,可以使用 countlengthsize 检索数组中的元素数。数组的同一属性使用不同的词,但是通过这种方式,Ruby 可以让您为代码选择最合适的词:您想要收集的项目的 number 个,数组的长度,或结构的当前大小。本质上,它们都是相同的,但是选择正确的词可能会使您的代码更易于阅读,这是该语言的一个很好的属性。
K
Kelvin

我被告知他们是一样的。

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

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

ary.collect {|项目|块 } → new_ary ary.map {|item| block } → 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"]


B
BrunoF

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

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

k
ktec

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

这是基准代码:

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) 

也许别名不是免费的?


我不确定这些差异是否显着。在重新运行时,我得到不同的速度结果(即使您的哈希收集似乎更慢,您的数组收集似乎更快)
j
jeton

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


我希望文档明确说明它们是别名。目前它们只是相互引用,两者的描述略有不同。
J
Junaid Abbasi

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