重複の可能性:
ruby配列内の重複要素をカウントします
私はルビーを学び始めたばかりで、このようなことを達成したいと思っています。配列があるとしましょう
["student", "student", "teacher", "teacher", "teacher"]
私がやろうとしているのは、生徒と教師の数を数えてハッシュに保存することです。
{:student= > 2, :teacher=> 3}
誰かが私にこれを行う方法について何らかの指示を与えることができますか?
重複の可能性:
ruby配列内の重複要素をカウントします
私はルビーを学び始めたばかりで、このようなことを達成したいと思っています。配列があるとしましょう
["student", "student", "teacher", "teacher", "teacher"]
私がやろうとしているのは、生徒と教師の数を数えてハッシュに保存することです。
{:student= > 2, :teacher=> 3}
誰かが私にこれを行う方法について何らかの指示を与えることができますか?
この答えを確認する必要があります。これにより、次の例が得られます。
# 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
list = ["student", "student", "teacher"]
# Initializing the hash with value 0 so that we can use += 1
count = Hash.new(0)
list.each {|el| count[el] += 1}
#Number of student
count['student']
xs.inject({}) { |acc, x| acc.update(x => (acc[x] || 0) + 1) }
#=> {"student"=>2, "teacher"=>3}
または:
xs.each_with_object(Hash.new(0)) { |x, acc| acc[x] += 1 }
#=> {"student"=>2, "teacher"=>3}
この特定の問題は、適切なアルゴリズムを選択する方法の優れた例ですが、さらに重要なことに、適切なデータ構造によってソリューションを大幅に簡素化できます。実際、この特定のケースでは、適切なデータ構造を選択すると、アルゴリズムが非常に簡単になり、基本的に完全に消滅します。データ構造はすでに答えです。
私が話しているデータ構造はMultiset
:aMultiset
に似てSet
いますが、一意のアイテムだけを格納するのではなく、各アイテムがに含まれる頻度のカウントを格納する点が異なりますMultiset
。基本的に、Set
は特定のアイテムがに含まれているかどうかSet
を示し、Multiset
さらにその特定のアイテムがに含まれている頻度Multiset
も示します。
残念ながら、Multiset
Rubyコアライブラリまたは標準ライブラリには実装がありませんが、Web上にいくつかの実装があります。
あなたは文字通りあなたMultiset
からを構築する必要がありますArray
。次に例を示します。
require 'multiset'
ary = ["student", "student", "teacher", "teacher", "teacher"]
print Multiset[*ary]
はい、それだけです。これは印刷します:
#2 "student"
#3 "teacher"
以上です。例、https ://GitHub.Com/Josh/Multimap/を使用:
require 'multiset'
histogram = Multiset.new(*ary)
# => #<Multiset: {"student", "student", "teacher", "teacher", "teacher"}>
histogram.multiplicity('teacher')
# => 3
例、 http: //maraigue.hhiro.net/multiset/index-en.phpを使用:
require 'multiset'
histogram = Multiset[*ary]
# => #<Multiset:#2 'student', #3 'teacher'>
もう1つの可能性は、を使用することHash
です。これは、基本的にMultiset
、要素のカウントを処理する代わりに、自分で実行する必要があることを意味します。
histogram = ary.inject(Hash.new(0)) {|hsh, item| hsh.tap { hsh[item] += 1 }}
print histogram
# { "student" => 2, "teacher" => 3 }
Enumerable#group_by
ただし、自分で数える代わりに、要素を自分でグループ化してから、グループ化をそれらのサイズにマップすることで、これを簡単に行うことができます。最後に、に変換し直しますHash
:
Identity = ->x { x }
print Hash[[ary.group_by(&Identity).map {|n, ns| [n, ns.size] }]
# { "student" => 2, "teacher" => 3 }
それは本当にここSOで死ぬまで行われていますが、私は提案します:
Hash[*a.group_by{|x| x}.flat_map{|k, v| [k.to_sym,v.size]}]
#=> {:student=>2, :teacher=>3}
a = ["student", "student", "teacher", "teacher", "teacher"]
a.inject({}){|h, e| h[e] ||= a.count(e); h}
# => {"student"=>2, "teacher"=>3}
list = ["student", "student", "teacher", "teacher", "teacher"] #original list
counts = {} #where the count hash will be
list.uniq.map{|x| counts[x]= list.count(x)}
リスト内のすべての一意のアイテムについて、元のリストからのカウントをカウントハッシュに入れます。
1行。清潔でシンプル。