[ruby] 루비에서 맵과 수집의 차이점은 무엇입니까?
나는 이것을 구글 검색했고 불쾌하고 모순 된 의견을 얻었 습니다. 루비 / 레일에서 배열을 map
수행하는 collect
것과 배열을 수행하는 것 사이에 실제로 차이점이 있습니까?
문서는 어떤을 제안하지 않는 것,하지만 방법이나 성능의 차이는 아마도이 있습니까?
답변
가지 사실에 차이는 없다 map
로 C로 구현 rb_ary_collect
하고 enum_collect
(예. 차이가 map
어레이에서 다른 어떤 ENUM에가 있지만 차이 사이 map
및 collect
).
왜 둘 다 할 map
과 collect
루비에 존재 하는가? 이 map
기능에는 여러 언어로 된 많은 명명 규칙이 있습니다. Wikipedia는 개요를 제공합니다 .
map 함수는 함수형 프로그래밍 언어에서 시작되었지만 오늘날 많은 절차 적, 객체 지향 및 다중 패러다임 언어에서도 지원됩니다 (또는 정의 될 수도 있음). C ++의 표준 템플릿 라이브러리에서는
transform
C # (3.0)에서이라고합니다. LINQ 라이브러리는이라는 확장 메소드로 제공됩니다Select
. 맵은 Perl, Python 및 Ruby와 같은 고급 언어에서 자주 사용되는 작업입니다. 이map
세 가지 언어 모두에서 작업이 호출 됩니다. Ruby의 스몰 토크 (Smalltalk) [emphasis mine] 에서도지도 의collect
별칭이 제공됩니다 . 커먼 리스프는 맵과 유사한 기능을 제공합니다. 여기에 설명 된 동작에 해당하는 것을 호출합니다mapcar
(-car는 CAR 조작을 사용하여 액세스를 나타냄).
루비는 스몰 토크 (Smalltalk) 세계의 프로그래머가 집에서 더 많이 느끼도록 별칭을 제공합니다.
왜 배열과 열거 형에 대해 다른 구현이 있습니까? 열거 형은 일반화 된 반복 구조로, Ruby가 다음 요소가 무엇인지 예측할 수있는 방법이 없습니다 (무한 열거 형을 정의 할 수 있습니다 ( 예 : Prime 참조 )). 따라서 각 연속 요소를 가져 오려면 함수를 호출해야합니다 (일반적으로 이것이 each
메소드가 됨).
어레이는 가장 일반적인 모음이므로 성능을 최적화하는 것이 합리적입니다. 루비는 배열의 작동 방식에 대해 많이 알고 있기 때문에 호출 each
할 필요는 없지만 간단한 포인터 조작 만 사용할 수 있어 훨씬 빠릅니다.
유사 최적화와 같은 배열 방법 중 다수 존재 zip
나 count
.
답변
나는 그들이 같다고 들었 습니다.
실제로 그것들은 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)
별명은 무료가 아닐까요?
답변
collect
및 collect!
방법에 별칭 map
과 map!
그들이 의미로 사용 할 수 있습니다. 다음을 쉽게 확인할 수 있습니다.
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;
}