[ruby] 루비에서 맵과 수집의 차이점은 무엇입니까?

나는 이것을 구글 검색했고 불쾌하고 모순 된 의견을 얻었 습니다. 루비 / 레일에서 배열을 map수행하는 collect것과 배열을 수행하는 것 사이에 실제로 차이점이 있습니까?

문서는 어떤을 제안하지 않는 것,하지만 방법이나 성능의 차이는 아마도이 있습니까?



답변

가지 사실에 차이는 없다 map로 C로 구현 rb_ary_collect하고 enum_collect(예. 차이가 map어레이에서 다른 어떤 ENUM에가 있지만 차이 사이 mapcollect).


왜 둘 다 할 mapcollect루비에 존재 하는가? map기능에는 여러 언어로 된 많은 명명 규칙이 있습니다. Wikipedia는 개요를 제공합니다 .

map 함수는 함수형 프로그래밍 언어에서 시작되었지만 오늘날 많은 절차 적, 객체 지향 및 다중 패러다임 언어에서도 지원됩니다 (또는 정의 될 수도 있음). C ++의 표준 템플릿 라이브러리에서는 transformC # (3.0)에서이라고합니다. LINQ 라이브러리는이라는 확장 메소드로 제공됩니다 Select. 맵은 Perl, Python 및 Ruby와 같은 고급 언어에서 자주 사용되는 작업입니다. 이 map세 가지 언어 모두에서 작업이 호출 됩니다. Ruby의 스몰 토크 (Smalltalk) [emphasis mine] 에서도지도 collect별칭이 제공됩니다 . 커먼 리스프는 맵과 유사한 기능을 제공합니다. 여기에 설명 된 동작에 해당하는 것을 호출합니다 mapcar(-car는 CAR 조작을 사용하여 액세스를 나타냄).

루비는 스몰 토크 (Smalltalk) 세계의 프로그래머가 집에서 더 많이 느끼도록 별칭을 제공합니다.


왜 배열과 열거 형에 대해 다른 구현이 있습니까? 열거 형은 일반화 된 반복 구조로, Ruby가 다음 요소가 무엇인지 예측할 수있는 방법이 없습니다 (무한 열거 형을 정의 할 수 있습니다 ( 예 : Prime 참조 )). 따라서 각 연속 요소를 가져 오려면 함수를 호출해야합니다 (일반적으로 이것이 each메소드가 됨).

어레이는 가장 일반적인 모음이므로 성능을 최적화하는 것이 합리적입니다. 루비는 배열의 작동 방식에 대해 많이 알고 있기 때문에 호출 each할 필요는 없지만 간단한 포인터 조작 만 사용할 수 있어 훨씬 빠릅니다.

유사 최적화와 같은 배열 방법 중 다수 존재 zipcount.


답변

나는 그들이 같다고 들었 습니다.

실제로 그것들은 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"]

답변

나는이 질문에 답을하기 위해 벤치 마크 테스트를 수행 한 다음이 게시물을 찾았으므로 내 결과 (다른 답변과 약간 다름)가 있습니다.

벤치 마크 코드는 다음과 같습니다.

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) 

별명은 무료가 아닐까요?


답변

collectcollect!방법에 별칭 mapmap!그들이 의미로 사용 할 수 있습니다. 다음을 쉽게 확인할 수 있습니다.

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


답변

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


답변