有没有更好的解决方案将哈希分成两个哈希?

时间:2014-05-14 09:14:30

标签: ruby

我写了一个方法,根据条件(特定的哈希值)将哈希分成两个哈希值。我的问题与another question on Hash不同。这是我期望的一个例子:

h={
  :a => "FOO",
  :b => "FOO",
  :c => "BAR",
  :d => "BAR",
  :e => "FOO"
}

h_foo, h_bar = partition(h)

我需要h_fooh_bar

h_foo={
  :a => "FOO",
  :b => "FOO",
  :e => "FOO"
} 

h_bar={
  :c => "BAR",
  :d => "BAR"
} 

我的解决方案是:

def partition h
  h.group_by{|k,v| v=="FOO"}.values.collect{|ary| Hash[*ary.flatten]}
end

有一个聪明的解决方案吗?

3 个答案:

答案 0 :(得分:5)

Enumerable#partition

h.partition { |k, v| v == "FOO" }.map(&:to_h)
#=> [{:a=>"FOO", :b=>"FOO", :e=>"FOO"}, {:c=>"BAR", :d=>"BAR"}]

或者您可以使用Enumerable#each_with_object来避免中间数组:

h.each_with_object([{}, {}]) { |(k, v), (h_foo, h_bar)|
  v == "FOO" ? h_foo[k] = v : h_bar[k] = v
}
#=> [{:a=>"FOO", :b=>"FOO", :e=>"FOO"}, {:c=>"BAR", :d=>"BAR"}]

答案 1 :(得分:0)

为什么不使用内置partition,这几乎完全符合您的要求?

h_foo, h_bar = h.partition { |key, value| value == 'FOO' }

唯一的缺点是你将获得数组而不是哈希(但你已经知道如何转换它)。在ruby 2.1+中,您只需在调用链的末尾调用.map(&:to_h)即可。

答案 2 :(得分:-1)

我不认为有一个聪明的单行,但你可以通过做类似的事情使它更通用:

def transpose(h,k,v)
  h[v] ||= []
  h[v] << k
end

def partition(h)
  n = {}
  h.map{|k,v| transpose(n,k,v)}
  result = n.map{|k,v| Hash[v.map{|e| [e, k]}] }
end

将产生

[{:a=>"FOO", :b=>"FOO", :e=>"FOO"}, {:c=>"BAR", :d=>"BAR"}]

针对您的初始哈希h

运行时

编辑 - 关于partition的TIL。恶