将嵌套哈希表压平为数组

5
我想将嵌套的哈希表压平为一个数组。例如:
a = {'1'=>{'2'=>{'5'=>{},'6'=>{'8'=>{}}}},'3'=>{},'4'=>{'7'=>{}}}

flatten_nested_hash(a)的结果将会是:

["1", "2", "5", "6", "8", "3", "4", "7"]

最后我写了一些递归函数,但我感觉肯定有更简单、非递归的方法。

我的函数看起来像这样:

  def flatten_nested_hash(categories)
    categories.map do |k,v|
      if v == {} 
        k
      else
        [k,flatten_nested_hash(v)]
      end
    end.flatten
  end

@raam86 PHP和Ruby是完全不同的编程语言。也许有某个重复的地方,但绝对不是那一个。 - Mischa
@Mischa 我完全同意。必须说我也懒得自己生成评论。已修复。 - raam86
可以从另一个角度来看待这个问题。 - raam86
5个回答

15

递归。

def flatten_nested_hash(categories)
  categories.flat_map{|k, v| [k, *flatten_nested_hash(v)]}
end

定义它在哈希类上。

class Hash
  def flatten_nested; flat_map{|k, v| [k, *v.flatten_nested]} end
end

5

在Ruby 2.1及更高版本中,您可以使用“refinements”将一个方法添加到Hash中,并仅在需要的模块/类中公开它。

module HashRefinements
  refine Hash do
    def flatten_nested
      flat_map { |k, v| [k, *v.flatten_nested] }
    end
  end
end

在你的类/模块中

class MyThing
  using HashRefinements

  ...

  def flatten_categories
    categories.flatten_nested
  end

  ...
end

3

这是一个嵌套的数据结构 - 你需要使用一些递归或迭代的方法来提取所有的key。但这比你现在拥有的要容易一些:

def deep_extract_keys(hash)
  hash.keys + hash.values.flat_map {|value| deep_extract_keys value }
end

p deep_extract_keys({"1"=>{"2"=>{"5"=>{}, "6"=>{"8"=>{}}}}, "3"=>{}, "4"=>{"7"=>{}}})

这是一种广度优先搜索,而不是深度优先搜索,因此输出结果为:
["1", "3", "4", "2", "5", "6", "8", "7"]

2
这会改变元素的顺序。 - sawa

0
module Flattener
  def deep_flatten
    flatten.map do |item|
      case item
      when Hash, Array
        item.deep_flatten
      else
        item
      end
    end.flatten
  end
end

class Hash

  include Flattener

end

class Array

  include Flattener

end

0

这不是(显式)递归,仅适用于非负整数键:

a.to_s.scan(/\d+/).map(&:to_i)   # [1, 2, 5, 6, 8, 3, 4, 7]

:-)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接