Ruby:反转哈希以保留非唯一值
我有一个看起来像这样的哈希:
{"a" => [1, 2, 3], "b" => [4, 5, 6], "c" => [3, 4, 5], "d" => [7, 2, 3]}
我想要做的是使用包含它的所有键的数组来创建所有现有值的哈希值,例如将上面的内容转换为:
{1 => ["a"], 2 => ["a", "d"], 3 => ["a", "c", "d"], 4 => ["b", "c"]}
我更喜欢@Jikku的解决方案,但总有另一种方式。 这是一个。 [编辑:我认为这与@Chris的解决方案非常接近。 我将把它留给最后一行,这有点不同。]
码
def inside_out(h) g = h.flat_map { |s,a| a.product([s]) } .group_by(&:first) g.merge(g) { |_,a| a.map(&:last) } end
例
h = {"a" => [1, 2, 3], "b" => [4, 5, 6], "c" => [3, 4, 5], "d" => [7, 2, 3]} inside_out(h) #=> {1=>["a"], 2=>["a", "d"], 3=>["a", "c", "d"], 4=>["b", "c"], # 5=>["b", "c"], 6=>["b"], 7=>["d"]}
说明
对于以上h
:
a = h.flat_map { |s,a| a.product([s]) } #=> [[1, "a"], [2, "a"], [3, "a"], [4, "b"], [5, "b"], [6, "b"], # [3, "c"], [4, "c"], [5, "c"], [7, "d"], [2, "d"], [3, "d"]] g = a.group_by(&:first) #=> {1=>[[1, "a"]], 2=>[[2, "a"], [2, "d"]], # 3=>[[3, "a"], [3, "c"], [3, "d"]], # 4=>[[4, "b"], [4, "c"]], # 5=>[[5, "b"], [5, "c"]], # 6=>[[6, "b"]], # 7=>[[7, "d"]]} g.merge(g) { |_,a| a.map(&:last) } #=> {1=>["a"], 2=>["a", "d"], 3=>["a", "c", "d"], 4=>["b", "c"], # 5=>["b", "c"], 6=>["b"], 7=>["d"]}
试试这个:
module HashReverser def invert_map each_with_object({}) do |(key, value), result| value.each { |v| (result[v] ||= []) << key } end end end original = {"a" => [1, 2, 3], "b" => [4, 5, 6], "c" => [3, 4, 5]} original.extend(HashReverser).invert_map # => {1=>["a"], 2=>["a"], 3=>["a", "c"], 4=>["b", "c"], 5=>["b", "c"], 6=>["b"]}
另一种解决方案:
# Given h = {"a" => [1, 2, 3], "b" => [4, 5, 6], "c" => [3, 4, 5], "d" => [7, 2, 3]} h.flat_map {|k, v| v.product [k]}.group_by(&:first).each_value {|v| v.map! &:last }
要么:
h.flat_map {|k, v| v.product [k]}.reduce({}) {|o, (k, v)| (o[k] ||= []) << v; o}
这里的想法是我们使用Array#product
来创建反向单键值对的列表:
product = h.flat_map {|k, v| v.product([k]) } # => [[1, "a"], [2, "a"], [3, "a"], [4, "b"], [5, "b"], [6, "b"], [3, "c"], [4, "c"], [5, "c"], [7, "d"], [2, "d"], [3, "d"]]
按每对中第一项的值对它们进行分组:
groups = product.group_by(&:first) # => {1=>[[1, "a"]], 2=>[[2, "a"], [2, "d"]], 3=>[[3, "a"], [3, "c"], [3, "d"]], 4=>[[4, "b"], [4, "c"]], 5=>[[5, "b"], [5, "c"]], 6=>[[6, "b"]], 7=>[[7, "d"]]}
然后将值转换为每对中最后一个值的列表:
result = groups.each_value {|v| v.map! &:last } # => {1=>["a"], 2=>["a", "d"], 3=>["a", "c", "d"], 4=>["b", "c"], 5=>["b", "c"], 6=>["b"], 7=>["d"]}
- 为什么x-editable-rails gem抛出一个错误:未定义的方法`xeditable?’?
- 我需要从HTML到降价,任何建议?
- Rails 3.1 hash每个都给出TypeError
- RefineryCMS Engines错误:没有有效的gemspec
- time_ago_in_words并本地化
- 当前的Ruby方法是通过super调用的吗?
- ruby prawn如何围绕对齐的右图包装文字?
- 您的Ruby版本是2.1.0,但您的Gemfile指定为2.0.0
- postgresql datababse出错:服务器是否在本地运行并接受Unix域套接字“/var/run/postgresql/.s.PGSQL.5432”上的连接?