可能重复:
计算 ruby 数组中的重复元素
我刚开始学习 ruby,我希望实现这样的目标。假设我有一个数组
["student", "student", "teacher", "teacher", "teacher"]
我要做的是计算学生和老师的数量并将其存储到哈希中,这样我就可以得到
{:student= > 2, :teacher=> 3}
有人可以给我一些关于如何做到这一点的方向吗?
可能重复:
计算 ruby 数组中的重复元素
我刚开始学习 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}
这个特殊问题是如何选择正确算法的一个很好的例子,但更重要的是正确的数据结构可以大大简化解决方案。事实上,在这种特殊情况下,选择正确的数据结构将使算法变得如此微不足道,以至于它基本上完全消失了:数据结构已经是答案。
我正在谈论的数据结构是 a Multiset
: aMultiset
就像 a Set
,除了它不只存储唯一项目,而是存储每个项目在Multiset
. 基本上,aSet
告诉您某个特定项目是否在 中Set
,此外,aMultiset
还告诉您该特定项目在 中的频率Multiset
。
不幸的是,Ruby 核心库或标准库中没有Multiset
实现,但有几个实现在网络上流传。
你实际上只需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'>
另一种可能性是使用 a Hash
,这基本上只是意味着Multiset
您不必为您处理元素计数,而是必须自己做:
histogram = ary.inject(Hash.new(0)) {|hsh, item| hsh.tap { hsh[item] += 1 }}
print histogram
# { "student" => 2, "teacher" => 3 }
但是,如果您不计算自己,而是使用自己Enumerable#group_by
对元素进行分组,然后将分组映射到它们的大小,那么您可以更容易地做到这一点。最后,转换回 a Hash
:
Identity = ->x { x }
print Hash[[ary.group_by(&Identity).map {|n, ns| [n, ns.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)}
对于列表中的每个唯一项目,将其从原始列表中的计数放入计数哈希中。
一条线。干净简单。
在 SO 上,它真的已经死了,但我建议:
Hash[*a.group_by{|x| x}.flat_map{|k, v| [k.to_sym,v.size]}]
#=> {:student=>2, :teacher=>3}