2011-01-14 13 views
11

Me pregunto si hay una manera más canónica de hacer esto en Ruby 1.9Hash edificio mediante la agrupación de matriz de objetos basado en una propiedad de los objetos

tengo una matriz con un montón de objetos y quiero para agruparlos en una Hash usando una propiedad de cada objeto en la matriz.

Muy ejemplo simplificado:

> sh = {} 
=> {} 
> aers = %w(a b c d ab bc de abc) 
=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"] 
> aers.each do |aer| 
>  sh[aer.size] = [] if sh[aer.size].nil? 
>  sh[aer.size] << aer 
> end 
=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"] 
> sh 
=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} 

He intentado esto, pero su producción está mal (como se puede ver):

sh = Hash.new([]) 
=> {} 
> aers.each do |aer| 
>  sh[aer.size] << aer 
> end 
=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"] 
> sh 
=> {} 
+2

Y la razón de su código no está funcionando como se esperaba se explica aquí: http://stackoverflow.com/questions/2698460/strange-ruby-behavior-when-using -hash-new y aquí: http://stackoverflow.com/questions/2552579/ruby-method-array-not-updating-the-array-in-hash (un error bastante común en Ruby). –

Respuesta

30

Rubí se ha anticipado a sus necesidades, y que ha conseguido cubierto con Enumerable#group_by:

irb(main):001:0> aers = %w(a b c d ab bc de abc) 
#=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"] 

irb(main):002:0> aers.group_by{ |s| s.size } 
#=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} 

En R uby 1.9, se puede hacer esto aún más corto con:

irb(main):003:0> aers.group_by(&:size) 
#=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} 
+3

Es por eso que Ruby es tan genial; Sabe lo que queremos incluso antes que nosotros. –

+0

Por favor, no en el símbolo 1.8 para que el proceso sea mucho más lento que usar el bloque. http://confreaks.net/videos/427-rubyconf2010-zomg-why-is-this-code-so-slow check 31:18. En 1.9 no son diferencias en el rendimiento. –

1

Usted también puede lograr esto mediante el encadenamiento de métodos ... que sólo puedan ser de interés académico para este problema, pero sigue siendo una buena técnica para estar familiarizado con .

irb(main):017:0> sh = {} 
=> {} 
irb(main):018:0> aers.collect{|k| k.size}.uniq!.each{|k| sh[k] = aers.select{|j| j.size == k}} 
=> [1, 2, 3] 
irb(main):019:0> sh 
=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} 
irb(main):020:0> 
3

Phrogz es correcto, group_by está ahí para tomarlo. Tu código contiene uno de los gotcha's de Ruby.

aers = %w(a b c d ab bc de abc) 
sh = Hash.new([]) # returns the _same_ array everytime the key is not found. 
# sh = Hash.new{|h,v| h[v] = []} # This one works 
p sh, sh.default 

aers.each do |aer| 
    sh[aer.size] << aer #modifies the default [] every time 
end 
p sh, sh.default 
p sh[5] 

salida

{} 
[] 
{} 
["a", "b", "c", "d", "ab", "bc", "de", "abc"] 
["a", "b", "c", "d", "ab", "bc", "de", "abc"] 
Cuestiones relacionadas