哈希值和值的频率

时间:2014-11-25 13:44:59

标签: ruby-on-rails ruby hash

我在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

感谢您的帮助,

微米。

2 个答案:

答案 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没有密钥kh[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的值。