Contare frequenza su array


#1

ciao a tutti
sto imparando Ruby; per me uno degli aspetti più ostici è capire come
produrre codice ben scritto; Ruby dà la libertà di scegliere fra tanti
modi diversi per ottenere un certo risultato; rimane sempre il dubbio
che esista una strada migliore di quella intrapresa; ad esempio, come si
fa a ottenere la frequenza degli elementi di un array? personalmente ho
prodotto il seguente codice:
a = [1,2,3,4,1,2,3,1,2,1,5,5]
b = {}
a.uniq.each {|x| b[x] = a.find_all {|y| y == x}.size}
p b
che produce
{5=>2, 1=>4, 2=>3, 3=>2, 4=>1}
esistono modi più puliti o efficienti di ottenere lo stesso risultato?
c’è modo di scrivere su un’unica riga la parte
b = {}
a.uniq.each {|x| b[x] = a.find_all {|y| y == x}.size}
p b
?
grazie


#2

On Wed, Feb 4, 2009 at 8:19 AM, Giampiero Z. removed_email_address@domain.invalid wrote:

che esista una strada migliore di quella intrapresa; ad esempio, come si
fa a ottenere la frequenza degli elementi di un array? personalmente ho
prodotto il seguente codice:
a = [1,2,3,4,1,2,3,1,2,1,5,5]

Io farei
così:
a.inject(Hash.new(0)) { |hash, item| hash[item] += 1; hash }

Ciao,
Antonio

http://antoniocangiano.com - Zen and the Art of Programming
http://math-blog.com - Mathematics is wonderful!
http://stacktrace.it - Aperiodico di resistenza informatica
Currently writing “Ruby on Rails for Microsoft Developers” for Wrox.


#3

Antonio C. wrote:

Io farei
cos�:
a.inject(Hash.new(0)) { |hash, item| hash[item] += 1; hash }

Ciao,
Antonio

intanto grazie mille per la pronta risposta
ecco, avevo visto giusto che c’era una via più breve e pulita; anch’io
avevo tentato la strada con inject, ma non avevo trovato il modo di
indicare che volevo ‘totalizzare’ su un hash inizialmente vuoto; fra
l’altro ho notato che se faccio precedere il tutto da p
p a.inject(Hash.new(0)) { |hash, item| hash[item] += 1; hash }
ottengo in output proprio l’hash; quindi la inject ritorna proprio
l’oggetto su cui ho ‘totalizzato’;
Ruby è troppo perfetto! fa sempre quello che ti aspetti


#4

On Wed, Feb 4, 2009 at 8:37 AM, Giampiero Z. removed_email_address@domain.invalid wrote:

Giampiero Z. wrote:
ah, no, l’ho capito solo ora; è grazie a ; hash alla fine del blocco che
ho l’hash come oggetto ritornato; dico bene? ho imparato un’altra cosa,

Esattamente. L’ultima espressione valutata nel blocco sarà il valore
di ritorno per la prossima iterazione, per cui ci serve hash che
agisce come accumulatore.

Ciao,
Antonio

http://antoniocangiano.com - Zen and the Art of Programming
http://math-blog.com - Mathematics is wonderful!
http://stacktrace.it - Aperiodico di resistenza informatica
Currently writing “Ruby on Rails for Microsoft Developers” for Wrox.


#5

Giampiero Z. wrote:
ah, no, l’ho capito solo ora; è grazie a ; hash alla fine del blocco che
ho l’hash come oggetto ritornato; dico bene? ho imparato un’altra cosa,
grazie di nuovo


#6

On 2/4/09 2:19 PM, Giampiero Z. wrote:

p b
che produce
{5=>2, 1=>4, 2=>3, 3=>2, 4=>1}
esistono modi più puliti o efficienti di ottenere lo stesso risultato?
c’è modo di scrivere su un’unica riga la parte
b = {}
a.uniq.each {|x| b[x] = a.find_all {|y| y == x}.size}
p b

La soluzione più elegante che mi venga in mente su 2 piedi:

a.inject(Hash.new(0)) { |h, v| h[v] += 1; h }

Una soluzione “offuscante” può essere:

b = Hash.new(0)
a.each { |x| b.merge!({x => 1}) { |k, o, n| o+n } }

Andrea


#7

Giampiero Z. wrote:

b = Hash.new(0)
a.each { |x| b.merge!({x => 1}) { |k, o, n| o+n } }

Andrea
grazie Andrea
la tua prima soluzione è praticamente identica a quella di Antonio; se
si ripete mi sa che è “la più giusta assai” :slight_smile:
per la seconda sono sempre qui che mi scervello, eppure funziona!!! più
che altro non capisco chi “chiama” il secondo blocco (?!?)

ah, ho capito; non conoscevo questa variante della merge; imparata una
nuova cosa;
grazie mille e a buon rendere (chissà ?!)
Giampiero


#8

La soluzione pi� elegante che mi venga in mente su 2 piedi:

a.inject(Hash.new(0)) { |h, v| h[v] += 1; h }

Una soluzione “offuscante” pu� essere:

b = Hash.new(0)
a.each { |x| b.merge!({x => 1}) { |k, o, n| o+n } }

Andrea
grazie Andrea
la tua prima soluzione è praticamente identica a quella di Antonio; se
si ripete mi sa che è “la più giusta assai” :slight_smile:
per la seconda sono sempre qui che mi scervello, eppure funziona!!! più
che altro non capisco chi “chiama” il secondo blocco (?!?)