Ich habe ein sortiertes Array:
[
'FATAL <error title="Request timed out.">',
'FATAL <error title="Request timed out.">',
'FATAL <error title="There is insufficient system memory to run this query.">'
]
Ich würde gerne so etwas bekommen, aber es muss kein Hash sein:
[
{:error => 'FATAL <error title="Request timed out.">', :count => 2},
{:error => 'FATAL <error title="There is insufficient system memory to run this query.">', :count => 1}
]
Sie können dies sehr prägnant (eine Zeile) tun, indem Sie Folgendes verwenden
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}" }
Wird herstellen:
1: FATAL <error title="There is insufficient ..."> 2: FATAL <error title="Request timed out.">
quelle
each_with_object
anstelle voninject
:a.each_with_object(Hash.new(0)) { |o, h| h[o] += 1 }
.each_with_object
da sie besser mit anderen ähnlichen Methodennamen auf Ruby- Enumerables übereinstimmt.each_with_object
den Code ein wenig vereinfacht, da der Akkumulator nicht der Rückgabewert des Blocks sein muss.Wenn Sie ein Array wie dieses haben:
words = ["aa","bb","cc","bb","bb","cc"]
Wenn Sie doppelte Elemente zählen müssen, ist eine einzeilige Lösung:
result = words.each_with_object(Hash.new(0)) { |word,counts| counts[word] += 1 }
quelle
Ein anderer Ansatz zu den obigen Antworten unter Verwendung von 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}
Das in seine verschiedenen Methodenaufrufe aufteilen:
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
wurde in Ruby 1.8.7 hinzugefügt.quelle
(&:itself)
, das ist genau die richtige Menge an Clever!Wie wäre es mit folgendem:
things = [1, 2, 2, 3, 3, 3, 4] things.uniq.map{|t| [t,things.count(t)]}.to_h
Es fühlt sich sauberer und aussagekräftiger an, was wir tatsächlich versuchen.
Ich vermute, dass es auch bei großen Sammlungen besser funktioniert als bei solchen, die über jeden Wert iterieren.
Benchmark-Leistungstest:
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)
Es ist also ziemlich viel schneller.
quelle
things.uniq
undthings.count(t)
iteriert über das Array?Persönlich würde ich es so machen:
# 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
Führen Sie dann das Programm aus und leiten Sie es an uniq -c weiter:
ruby myprogram.rb | uniq -c
Ausgabe:
2 FATAL <error title="Request timed out."> 1 FATAL <error title="There is insufficient system memory to run this query.">
quelle
Von Ruby> = 2.2 können Sie verwenden
itself
:array.group_by(&:itself).transform_values(&:count)
Mit etwas mehr Details:
array = [ 'FATAL <error title="Request timed out.">', 'FATAL <error title="Request timed out.">', 'FATAL <error title="There is insufficient system memory to run this query.">' ]; array.group_by(&:itself).transform_values(&:count) => { "FATAL <error title=\"Request timed out.\">"=>2, "FATAL <error title=\"There is insufficient system memory to run this query.\">"=>1 }
quelle
Ruby-Versionen> = 2.7 haben Enumerable # tally .
z.B:
["a", "b", "c", "b"].tally #=> { "a" => 1, "b" => 2, "c" => 1 }
quelle
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}]
quelle
Wenn Sie dies häufig verwenden möchten, empfehle ich Folgendes:
# lib/core_extensions/array/duplicates_counter module CoreExtensions module Array module DuplicatesCounter def count_duplicates self.each_with_object(Hash.new(0)) { |element, counter| counter[element] += 1 }.sort_by{|k,v| -v}.to_h end end end end
Laden Sie es mit
Array.include CoreExtensions::Array::DuplicatesCounter
Und dann von überall mit nur verwenden:
the_ar = %w(a a a a a a a chao chao chao hola hola mundo hola chao cachacho hola) the_ar.duplicates_counter { "a" => 7, "chao" => 4, "hola" => 4, "mundo" => 1, "cachacho" => 1 }
quelle
Einfache Implementierung:
(errors_hash = {}).default = 0 array_of_errors.each { |error| errors_hash[error] += 1 }
quelle
errors_hash = Hash.new(0)
Hier ist das Beispielarray:
a=["aa","bb","cc","bb","bb","cc"]
{'bb' => ['bb', 'bb']}
Jetzt können Sie Dinge tun wie:
res['aa'].size
quelle
def find_most_occurred_item(arr) return 'Array has unique elements already' if arr.uniq == arr m = arr.inject(Hash.new(0)) { |h,v| h[v] += 1; h } m.each do |k, v| a = arr.max_by { |v| m[v] } if v > a puts "#{k} appears #{v} times" elsif v == a puts "#{k} appears #{v} times" end end end puts find_most_occurred_item([1, 2, 3,4,4,4,3,3])
quelle