arr = [1,2,1,3,5,2,4]
如何通过排序按组值计算数组?我需要以下输出:
x[1] = 2
x[2] = 2
x[3] = 1
x[4] = 1
x[5] = 1
答案 0 :(得分:106)
x = arr.inject(Hash.new(0)) { |h, e| h[e] += 1 ; h }
答案 1 :(得分:31)
仅适用于ruby 1.9
基本上与Michael's answer相同,但稍微短一些:
x = arr.each_with_object(Hash.new(0)) {|e, h| h[e] += 1}
在类似的情况下,
Array
,Hash
,String
,则可以使用each_with_object
,如上面的案例。如果起始元素是不可变对象,例如Numeric
,则必须使用inject
,如下所示。
sum = (1..10).inject(0) {|sum, n| sum + n} # => 55
答案 2 :(得分:13)
另一个 - 与其他人相似 - 接近:
result=Hash[arr.group_by{|x|x}.map{|k,v| [k,v.size]}]
result[1]=2 ...
访问。答案 3 :(得分:10)
x = Hash[arr.uniq.map{ |i| [i, arr.count(i)] }]
答案 4 :(得分:9)
每当你发现有人声称某种东西在这种原始程序中是最快的时候,我总是觉得有趣的是要确认,因为没有确认我们大多数人真的只是在猜测。所以我在这里采用了所有方法并对它们进行了基准测试。
我从一个网页中提取了120个链接的数组,我需要按计数进行分组,并使用秒= Benchmark.realtime do循环实现所有这些,并且一直都有。
假设链接是我需要计算的数组的名称:
#0.00077
seconds = Benchmark.realtime do
counted_links = {}
links.each { |e| counted_links[e] = links.count(e) if counted_links[e].nil?}
end
seconds
#0.000232
seconds = Benchmark.realtime do
counted_links = {}
links.sort.group_by {|x|x}.each{|x,y| counted_links[x] = y.size}
end
#0.00076
seconds = Benchmark.realtime do
Hash[links.uniq.map{ |i| [i, links.count(i)] }]
end
#0.000107
seconds = Benchmark.realtime do
links.inject(Hash.new(0)) {|h, v| h[v] += 1; h}
end
#0.000109
seconds = Benchmark.realtime do
links.each_with_object(Hash.new(0)) {|e, h| h[e] += 1}
end
#0.000143
seconds = Benchmark.realtime do
links.inject(Hash.new(0)) { |h, e| h[e] += 1 ; h }
end
然后有点红宝石来找出答案:
times = [0.00077, 0.000232, 0.00076, 0.000107, 0.000109, 0.000143].min
==> 0.000107
所以实际上最快的方法,当然是ymmv:
links.inject(Hash.new(0)) {|h, v| h[v] += 1; h}
答案 5 :(得分:8)
arr.group_by(&:itself).transform_values(&:size)
#=> {1=>2, 2=>2, 3=>1, 5=>1, 4=>1}
答案 6 :(得分:5)
我相信有更好的方法,
>> arr.sort.group_by {|x|x}.each{|x,y| print "#{x} #{y.size}\n"}
1 2
2 2
3 1
4 1
5 1
根据需要将x和y值分配给哈希值。
答案 7 :(得分:5)
仅供记录,我最近阅读了Object#tap
here。我的解决方案是:
Hash.new(0).tap{|h| arr.each{|i| h[i] += 1}}
#tap
方法将调用者传递给块然后返回它。当你必须逐步构建数组/散列时,这非常方便。
答案 8 :(得分:4)
这应该这样做
arr = [1,2,1,3,5,2,4]
puts arr.inject(Hash.new(0)) {|h, v| h[v] += 1; h}
#=> {1=>2, 2=>2, 3=>1, 5=>1, 4=>1}
答案 9 :(得分:4)
ruby 2.7 => Enumerable#tally
中有一个简短的版本。
[1,2,1,3,5,2,4].tally #=> { 1=>2, 2=>2, 3=>1, 5=>1, 4=>1 }
# Other possible usage
(1..6).tally { |i| i%3 } #=> { 0=>2, 1=>2, 2=>2 }
答案 10 :(得分:1)
arr = [1,2,1,3,5,2,4]
r = {}
arr.each { |e| r[e] = arr.count(e) if r[e].nil?}
输出
p r
#==> {1=>2, 2=>2, 3=>1, 5=>1, 4=>1}