tamaño objects len item for array ruby arrays

objects - ruby select



Cómo contar elementos duplicados en una matriz de Ruby (9)

Tengo una matriz ordenada:

[ ''FATAL <error title="Request timed out.">'', ''FATAL <error title="Request timed out.">'', ''FATAL <error title="There is insufficient system memory to run this query.">'' ]

Me gustaría obtener algo como esto, pero no tiene que ser un hash:

[ {:error => ''FATAL <error title="Request timed out.">'', :count => 2}, {:error => ''FATAL <error title="There is insufficient system memory to run this query.">'', :count => 1} ]


¿Qué tal lo siguiente?

things = [1, 2, 2, 3, 3, 3, 4] things.uniq.map{|t| [t,things.count(t)]}.to_h

De alguna manera se siente más limpio y más descriptivo de lo que realmente estamos tratando de hacer.

Sospecho que también funcionaría mejor con colecciones grandes que las que iteran sobre cada valor.

Prueba de rendimiento de referencia:

a = (1...1000000).map { rand(100)} user system total real inject 7.670000 0.010000 7.680000 ( 7.985289) array count 0.040000 0.000000 0.040000 ( 0.036650) each_with_object 0.210000 0.000000 0.210000 ( 0.214731) group_by 0.220000 0.000000 0.220000 ( 0.218581)

Entonces es bastante más rápido.


Aquí está la matriz de muestra:

a=["aa","bb","cc","bb","bb","cc"]

  1. Seleccione todas las claves únicas.
  2. Para cada clave, las acumularemos en un hash para obtener algo como esto: {''bb'' => [''bb'', ''bb'']}

res = a.uniq.inject({}) {|accu, uni| accu.merge({ uni => a.select{|i| i == uni } })} {"aa"=>["aa"], "bb"=>["bb", "bb", "bb"], "cc"=>["cc", "cc"]}

Ahora puedes hacer cosas como:

res[''aa''].size


El siguiente código imprime lo que solicitó. Dejaré que decidas cómo usar realmente para generar el hash que estás buscando:

# sample array a=["aa","bb","cc","bb","bb","cc"] # make the hash default to 0 so that += will work correctly b = Hash.new(0) # iterate over the array, counting duplicate entries a.each do |v| b[v] += 1 end b.each do |k, v| puts "#{k} appears #{v} times" end

Nota: Me di cuenta de que dijiste que la matriz ya está ordenada. El código anterior no requiere clasificación. Usar esa propiedad puede producir código más rápido.


Implementación simple:

(errors_hash = {}).default = 0 array_of_errors.each { |error| errors_hash[error] += 1 }


Personalmente lo haría de esta manera:

# myprogram.rb a = [''FATAL <error title="Request timed out.">'', ''FATAL <error title="Request timed out.">'', ''FATAL <error title="There is insufficient system memory to run this query.">''] puts a

A continuación, ejecute el programa y canalícelo a uniq -c:

ruby myprogram.rb | uniq -c

Salida:

2 FATAL <error title="Request timed out."> 1 FATAL <error title="There is insufficient system memory to run this query.">


Puede hacer esto de manera muy sucinta (una línea) usando inject :

a = [''FATAL <error title="Request timed out.">'', ''FATAL <error title="Request timed out.">'', ''FATAL <error title="There is insufficient ...">''] b = a.inject(Hash.new(0)) {|h,i| h[i] += 1; h } b.to_a.each {|error,count| puts "#{count}: #{error}" }

Producirá:

1: FATAL <error title="There is insufficient ..."> 2: FATAL <error title="Request timed out.">


Si tienes una matriz como esta:

words = ["aa","bb","cc","bb","bb","cc"]

donde necesita contar elementos duplicados, una solución de una línea es:

result = words.each_with_object(Hash.new(0)) { |word,counts| counts[word] += 1 }


Un enfoque diferente de las respuestas anteriores, utilizando Enumerable#group_by .

[1, 2, 2, 3, 3, 3, 4].group_by(&:itself).map { |k,v| [k, v.count] }.to_h # {1=>1, 2=>2, 3=>3, 4=>1}

Rompiendo eso en sus diferentes llamadas a métodos:

a = [1, 2, 2, 3, 3, 3, 4] a = a.group_by(&:itself) # {1=>[1], 2=>[2, 2], 3=>[3, 3, 3], 4=>[4]} a = a.map { |k,v| [k, v.count] } # [[1, 1], [2, 2], [3, 3], [4, 1]] a = a.to_h # {1=>1, 2=>2, 3=>3, 4=>1}

Enumerable#group_by se agregó en Ruby 1.8.7.


a = [1,1,1,2,2,3] a.uniq.inject([]){|r, i| r << { :error => i, :count => a.select{ |b| b == i }.size } } => [{:count=>3, :error=>1}, {:count=>2, :error=>2}, {:count=>1, :error=>3}]