我在Ruby中有以下哈希:
{
0 => {
:method=> "POST",
:path=> "/api/customer/191023",
:host=> "host.8",
:duration=> "1221"
},
1 => {
:method=> "GET",
:path=> "/api/customer/191023",
:host=> "host.8",
:duration=> "99"
},
2 => {
:method=> "POST",
:path=> "/api/customer/191023",
:host=> "host.10",
:duration=> "142"
},
3 => {
:method=> "POST",
:path=> "/api/customer/191023",
:host=> "host.8",
:duration=> "243"
}
4 => {
:method=> "POST",
:path=> "/api/customer/191023",
:host=> "host.10",
:duration=> "132"
}
}
我想在这些哈希中进行简单搜索,以找到频率最高的host
。例如,在前面的示例中,我应该获得host.8
。
感谢您的帮助,
微米。
答案 0 :(得分:2)
要查找频率最高的主机值,请执行以下操作:
hs = hash.values.group_by { |h| h[:host] =~ /host\.(\d+)/ && $1.to_i || 0 }.to_a
hs.reduce([-1,0]) { |sum,v| v[1].size > sum[1] && [ v[0], v[1].size ] || sum }.first
说明 [-1,0]
是#reduce
method设置的默认值,其中-1
是一个数字(如host.number
中所示),以及0
是数字的计数。因此,当reduce遇到大小超过传递sum
的数字时,它会在下一次迭代时替换为新值。
答案 1 :(得分:1)
这是实现这一目标的一种方法。
<强>代码强>
def max_host(hash)
hash.each_with_object(Hash.new(0)) { |(_,v),h| h[v[:host]] += 1 }
.max_by { |_,v| v }
.first
end
示例强>
我们来看下面的简化示例。请注意,我已将:host = \"host.10\"
更改为:host = "host.10"
,因为前者不是正确的语法。您可以将字符串写为'\"host.10\"
(=> "\\\"host.10\\\""
),但我认为您只需要"host.10"
。两者的代码相同。
hash = {
0 => {
:method=>"POST",
:host =>"host.8"
},
1 => {
:method=>"GET",
:host =>"host.10"
},
2 => {
:method=>"POST",
:host =>"host.10"
}
}
max_host(hash)
#=> "host.10"
<强>解释强>
对于上面的示例hash
,
enum = hash.each_with_object(Hash.new(0))
#=> #<Enumerator: {
# 0=>{:method=>"POST", :host=>"host.8"},
# 1=>{:method=>"GET", :host=>"host.10"},
# 2=>{:method=>"POST", :host=>"host.10"}}:each_with_object({})>
枚举器将调用方法Hash#each将枚举数的每个元素传递给块。我们可以通过将枚举器转换为数组来查看这些元素是什么:
enum.to_a
#=> [[[0, {:method=>"POST", :host=>"host.8"}], {}],
# [[1, {:method=>"GET", :host=>"host.10"}], {}],
# [[2, {:method=>"POST", :host=>"host.10"}], {}]]
第一个元素中显示的空哈希是
创建的哈希的初始值Hash.new(0)
这将创建一个默认值为零的哈希h
。通过这种方式,如果h
没有密钥k
,h[k]
将返回默认值(0
),但是(重要!)这不会改变哈希。
传递给块的第一个值是
[[0, {:method=>"POST", :host=>"host.8"}], {}]
然后将其分解(或消除歧义&#34;)为分配给三个块变量的单个对象:
k => 0
v => {:method=>"POST", :host=>"host.8"}
h => Hash.new(0)
然后我们执行:
h[v[:host]] += 1
是
h["host.8"] += 1
这是
的简写h["host.8"] = h["host.8"] + 1
[旁白:您可能已经注意到,在代码中我将块变量显示为|(_,v),h|
,而在上面我将它们称为|(k,v),h|
。我可以使用后者,但由于k
不是块中的引用,我选择将其替换为&#34;占位符&#34; _
。这样可以确保k
不被引用,并告诉任何读者我没有使用第一个块变量。]
由于h
没有密钥"host.8"
,h["host.8"]
右侧的=
会返回默认值:
h["host.8"] = 0 + 1
#=> 1
所以现在
h #=> {"host.8"=>1}
传递给块的第二个元素是
[[1, {:method=>"GET", :host=>"host.10"}], {"host.8"=>1}]
所以块变量变为:
v => {:method=>"GET", :host=>"host.10"}
h => {"host.8"=>1}
请注意,哈希h
已更新。我们执行
h[v[:host]] += 1
#=> h["host.10"] += 1
#=> h["host.10"] = h["host.10"] + 1
#=> h["host.10"] = 0 + 1
#=> 1
所以现在
h #=> {"host.8"=>1, "host.10"=>1}
最后,为块变量赋值
v = {:method=>"POST", :host=>"host.10"}
h => {"host.8"=>1, "host.10"=>1}
所以
h[v[:host]] += 1
#=> h["host.10"] += 1
#=> h["host.10"] = h["host.10"] + 1
#=> h["host.10"] = 1 + 1
#=> 2
h #=> {"host.8"=>1, "host.10"=>2}
,方法返回h
的值。