让我们说我有每行号文件:如何组号码分成不同的水桶红宝石
0101
1010
1311
0101
1311
431
1010
431
420
最后,我将不得不与每个号码的出现次数的哈希,在这种情况下, :
{0101 => 2, 1010 => 2, 1311 => 2, 431 => 2, 420 => 1}
我该怎么做到这一点?
让我们说我有每行号文件:如何组号码分成不同的水桶红宝石
0101
1010
1311
0101
1311
431
1010
431
420
最后,我将不得不与每个号码的出现次数的哈希,在这种情况下, :
{0101 => 2, 1010 => 2, 1311 => 2, 431 => 2, 420 => 1}
我该怎么做到这一点?
简单的一行,给定一个数组items
:
items.inject(Hash.new(0)) {|hash, item| hash[item] += 1; hash}
工作原理:
Hash.new(0)
创建一个新的Hash,其中访问未定义的键在一个数组返回0
inject(foo)
迭代与给定的块。对于第一次迭代,它通过foo
,并在进一步的迭代中传递最后一次迭代的返回值。
另一种方式来写这将是:
hash = Hash.new(0)
items.each {|item| hash[item] += 1}
ID = -> x { x } # Why is the identity function not in the core lib?
f = <<-HERE
0101
1010
1311
0101
1311
431
1010
431
420
HERE
Hash[f.lines.map(&:to_i).group_by(&ID).map {|n, ns| [n, ns.size] }]
# { 101 => 2, 1010 => 2, 1311 => 2, 431 => 2, 420 => 1 }
您只需组使用Enumerable#group_by
自己的数字,它给你像
{ 101 => [101, 101], 420 => [420] }
然后你Enumerable#map
值阵列到它们的长度,即[101, 101]
变成2
。然后使用Hash::[]
将其转换回Hash
。
但是,如果您愿意使用第三方库,它会变得更加微不足道,因为如果您使用MultiSet
数据结构,答案会自然而然地出现。 (A MultiSet
就像一个Set
,除了一个项目可以多次添加和MultiSet
将保留的项目是如何经常地加入 –这是你想要什么计数)。
require 'multiset' # Google for it, it's so old that it isn't available as a Gem
Multiset[*f.lines.map(&:to_i)]
# => #<Multiset:#2 101, #2 1010, #2 1311, #2 431, #1 420>
是的,这是它。
这是关于使用正确数据结构的美妙之处:您的算法变得非常简单。或者,在这种特殊情况下,算法消失。
我已经写了更多关于使用MultiSet
局长在
group_by
例子一样。)这是基本相同,Chuck的,但是当你创建一个数组或哈希,“each_with_object”将使它比'inject'稍微简单一些,因为您不必在块中编写最终数组或散列。
items.each_with_object(Hash.new(0)) {|item, hash| hash[item] += 1}
我想我发现与不同的措词对同一问题:) [计数红宝石阵列重复的元素](http://stackoverflow.com/questions/569694/count-duplicate-elements-in-ruby-array ) – Matchu 2010-11-29 01:17:24
:)多数民众赞成在伟大的。谢谢。 – josh 2010-11-29 01:21:19
仅供参考:如果碰巧是Rails,则可以使用Enumerable#group_by。请参阅http://api.rubyonrails.org/classes/Enumerable.html#method-i-group_by – 2010-11-29 16:36:53