Harita ve toplama Ruby arasındaki fark?


428

Ben bu Googled var ve düzensiz / çelişkili görüşler var - aslında yapmak mapve collectRuby / Rails bir dizi bir yapmak arasında herhangi bir fark var mı?

Docs herhangi önermek görünmüyor, ancak yöntemin veya performansındaki farklılıklar belki vardır?


5
mapCode Golf'te tercih edilmektedir .
Cary Swoveland

1
mapCodeGolf'ta neden herkes için açık olmayabilir, bunun neden tercih edildiğine dair bir açıklama olarak : sadece collectdört karakterden daha uzun map, ancak işlevsellikte aynı olduğu için.
Jochem Schulenklopper

2
Sadece şeytanın savunucusunu oynamak için, kişisel olarak collectdaha okunabilir ve doğal buluyorum - kayıtları 'toplama' ve onlara X yapma fikri bana 'kayıtları' haritalamaktan ve onlara X yapmaktan daha doğal bir anlam ifade ediyor.
sscirrus

Yanıtlar:


480

Aslında hiçbir fark yoktur mapve C olarak rb_ary_collectve enum_collect(örneğin map, bir dizi ve diğer numaralar arasında bir fark vardır , fakat mapve arasında bir fark yoktur collect).


Neden ikisini de mapve collectRuby var? mapFonksiyon farklı dillerde birçok adlandırma kuralları vardır. Wikipedia bir genel bakış sunar :

Harita işlevi işlevsel programlama dillerinden kaynaklanır, ancak bugün birçok yordamsal, nesne yönelimli ve çoklu paradigma dilinde de desteklenir (veya tanımlanabilir): C ++ 'ın Standart Şablon Kütüphanesinde, transformC # (3.0)' da denir. LINQ kütüphanesi, adı verilen bir uzantı yöntemi olarak sağlanır Select. Harita ayrıca Perl, Python ve Ruby gibi üst düzey dillerde sık kullanılan bir işlemdir; operasyon mapbu dillerin üçünde de çağrılır . Harita için bir collectdiğer ad da Ruby'de (Smalltalk'tan) [vurgu mayın]. Common Lisp, harita benzeri işlevler ailesi sağlar; burada açıklanan davranışa karşılık mapcargelene denir (-CAR işlemini kullanarak erişimi gösteren araç).

Ruby, Smalltalk dünyasından programcıların kendilerini evlerinde hissetmeleri için bir takma ad sağlar.


Diziler ve sıralamalar için neden farklı bir uygulama var? Bir enum genelleştirilmiş bir yineleme yapısıdır, yani Ruby'nin bir sonraki öğenin ne olabileceğini tahmin etmesinin bir yolu yoktur (sonsuz numaralandırmalar tanımlayabilirsiniz, bkz . Örnek için Prime ). Bu nedenle, birbirini izleyen her öğeyi almak için bir işlev çağırmalıdır (genellikle bu eachyöntem olacaktır ).

Diziler en yaygın koleksiyonlardır, bu nedenle performanslarını optimize etmek mantıklıdır. Ruby, dizilerin nasıl çalıştığı hakkında çok şey bildiğinden, aramak zorunda değildir, eachancak yalnızca önemli ölçüde daha hızlı olan basit işaretçi manipülasyonunu kullanabilir .

zipVeya gibi birçok Array yöntemi için benzer optimizasyonlar mevcuttur count.


14
@Mark Reed ancak daha sonra SmallTalk'tan gelmeyen programcılar, sadece takma adlar olarak ortaya çıkan iki farklı fonksiyona sahip olacaklardı. Yukarıdaki OP gibi sorulara neden olur.
SasQ

11
@SasQ Katılmıyorum - sadece bir isim olsaydı genel olarak daha iyi olacağını düşünüyorum. Ancak Ruby'de diğer birçok takma ad vardır ve takma adın bir özelliği, toplama , algılama , enjekte etme , reddetme ve seçme işlemleri arasında güzel bir adlandırma olmasıdır (aksi halde harita , bulma , azaltma , reddetme (takma ad yok) ) ve find_all ).
Mark Reed

5
Aslında. Görünüşe göre, Ruby diğer durumlarda takma adları / eş anlamlıları kullanıyor. Örneğin, bir dizideki elementlerin sayısı ile alınabilir count, lengthya da size. Farklı bir dizinin aynı özelliğe ilişkin sözler, ama bundan Ruby kodunuz için en uygun kelimeyi seçmek için sağlar: istiyorsun numarayı öğeleri Sen toplama, uzunluk bir dizinin veya geçerli boyutu arasında yapı. Esasen, hepsi aynı, ancak doğru sözcüğü seçmek, kodunuzun okunmasını kolaylaştırabilir, bu da dilin güzel bir özelliği.
Jochem Schulenklopper

52

Bana aynı oldukları söylendi .

Aslında ruby-doc.org altında aynı yerde belgeleniyorlar:

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

  • ary.collect {| öğe | engelle} → new_ary
  • ary.map {| öğe | engelle} → new_ary
  • ary.collect → an_enumerator
  • ary.map → an_enumerator

Her bir benlik elemanı için bloğu bir kez çağırır. Blok tarafından döndürülen değerleri içeren yeni bir dizi oluşturur. Ayrıca Numaralandırılabilir # toplamaya bakın.
Blok verilmezse, bunun yerine bir numaralandırıcı döndürülür.

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


14

Bu soruyu cevaplamak için bir test testi yaptım, sonra bu gönderiyi buldum, bu yüzden burada bulgularım (diğer cevaplardan biraz farklı)

Kıyaslama kodu:

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

Ve elde ettiğim sonuçlar:

                   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) 

Belki de bir takma ad ücretsiz değildir?


1
Bu farklılıkların önemli olup olmadığından emin değilim. Tekrarlama ben hız farklı sonuçlar elde (sizin karma toplamak yavaş görünüyor bile, senin dizi toplamak daha hızlı görünüyor)
mürb

11

collectVe collect!yöntemleri diğer adlar şunlardır mapve map!bunlar birbirinin yerine kullanılabilir, böylece. İşte bunu doğrulamanın kolay bir yolu:

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

8

Ruby, Array # collect ile Array # map; birbirinin yerine kullanılabilir. (Yakut Keşiş)

Başka bir deyişle, aynı kaynak kodu:

               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
Açıkça belirtilen belgelerin takma ad olmasını diliyorum. Şu anda sadece birbirlerine atıfta bulunuyorlar ve her ikisinin de biraz farklı açıklamaları var.
Chris Bloom
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.