2009-09-02 10 views

risposta

14
types = Hash.new(-1) # It feels like this should be 0, but to be 
        # equivalent to your example it needs to be -1 
array.each do |c| 
    types[c.type] += 1 
end 
+0

+1 per il commento. –

2

||= aiuta:

types = {} 
array.each do |c| 
    types[c.class] ||= 0 
    types[c.class] += 1 
end 
+2

Questo lo imposterà a 1 la prima volta attraverso ... newarray [c.type] || = -1 newarray [c.type] + = 1 –

+0

Sì, non è quello che vogliamo? Ad esempio, se array è [1], i tipi diventeranno {Fixnum => 1}. E abbiamo 1 Fixnum. –

+0

Vogliamo che sia impostato su 0 alla fine del ciclo, non 1, se! Tipi [c.class]. – Chuck

4
array.each do |c| 
    newarray[c.type] = 1 + (newarray[c.type] || -1) 
end 

alternativa

array.each do |c| 
    newarray[c.type] ||= -1 
    newarray[c.type] += 1 
end 
+1

Mi piace il tuo secondo. L'unico inconveniente è che è il tipo di cosa che qualcuno che viene dopo può prendere per essere un errore. Se lo si utilizza in produzione, aggiungerei un breve commento che spiega perché lo sto facendo in questo modo. – Pesto

+0

Mi piace il secondo modo. Si tratta di due linee e potenzialmente due assegnazioni, ma più leggibili rispetto a condizionali complessi o qualsiasi altra cosa spinto su una riga. – Chuck

6

Utilizzare il metodo Array#fetch per il quale è possibile fornire un valore predefinito se l'indice non esiste:

array.each do |c| 
    newarray[c.type] = newarray.fetch(c.type, -1) + 1 
end 
0

La variabile newarray è denominata in modo strano, poiché in Ruby e nella maggior parte degli altri linguaggi, gli array sono indicizzati da numeri interi, non oggetti casuali come Class. È più probabile che questo sia un Hash.

Inoltre, si dovrebbe usare c.class, anziché c.type, che è deprecato.

Infine, dal momento che si sta creando un Hash, è possibile utilizzare inject in questo modo:

newarray = array.inject({}) do |h,c| 
    h[c.class] = h.key?(c.class) ? h[c.class]+1 : 0 
    h 
end 

Oppure, per un one-liner:

newarray = array.inject({}) { |h,c| h[c.class] = h.key?(c.class) ? h[c.class]+1 : 0 ; h } 

Come si può vedere, questo dà i risultati desiderati:

irb(main):001:0> array = [1, {}, 42, [], Object.new(), [1, 2, 3]] 
=> [1, {}, 42, [], #<Object:0x287030>, [1, 2, 3]] 
irb(main):002:0> newarray = array.inject({}) { |h,c| h[c.class] = h.key?(c.class) ? h[c.class]+1 : 0 ; h } 
=> {Object=>0, Hash=>0, Array=>1, Fixnum=>1} 
0

In Ruby 1.8.7 o successivo è possibile utilizzare group_by e quindi trasformare ciascun elenco di elementi in count-1 e creare un hash dall'array restituito da map.

Hash[array.group_by(&:class).map { |k,v| [k, v.size-1] }] 
Problemi correlati