2009-09-02 10 views

Respuesta

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 para el comentario. –

2

||= ¿Ayuda:

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

Eso lo establecerá en 1 la primera vez a través de ... newarray [c.type] || = -1 newarray [c.type] + = 1 –

+0

Sí, ¿no es eso lo que queremos? Por ejemplo, si array es [1], los tipos se convertirán en {Fixnum => 1}. Y tenemos 1 Fixnum. –

+0

Queremos que se establezca en 0 al final del ciclo, no en 1, if! Types [c.class]. – Chuck

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

Alternativamente

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

Me gusta tu segundo. El único inconveniente es que es el tipo de cosa que alguien que viene después puede tomar por un error. Si lo uso en producción, agregaría un comentario rápido explicando por qué lo hago de esa manera. – Pesto

+0

Me gusta la segunda manera. Son dos líneas y, potencialmente, dos asignaciones, pero más legibles que condicionales complejos o lo que sea empujado en una línea. – Chuck

6

Utilice el método Array#fetch de la que puede proporcionar un valor por defecto si el índice no existe:

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

Su variable newarray se nombra de manera extraña, ya que en Ruby y en la mayoría de los demás idiomas, las matrices están indexadas por enteros, no por objetos aleatorios como Class. Es más probable que este sea un Hash.

Además, debe utilizar c.class, en lugar de c.type, que está en desuso.

Finalmente, puesto que se está creando un Hash, puede utilizar inject así:

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

O, para una sola línea:

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

Como se puede ver, esto da los resultados deseados:

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

En Ruby 1.8.7 o posterior, puede usar group_by y luego convierta cada lista de elementos en el recuento - 1, y haga un hash de la matriz devuelta por map.

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