Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flattening nested hash to an array

Tags:

ruby

I'd like to flatten nested hash to an array. For example:

a = {'1'=>{'2'=>{'5'=>{},'6'=>{'8'=>{}}}},'3'=>{},'4'=>{'7'=>{}}}

and result of flatten_nested_hash(a) would be:

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

Finally I wrote some recursive function, but I feel that there must be some easier, non-recursive way of doing it.

My function looks like this:

  def flatten_nested_hash(categories)
    categories.map do |k,v|
      if v == {} 
        k
      else
        [k,flatten_nested_hash(v)]
      end
    end.flatten
  end
like image 828
Marcin Doliwa Avatar asked Nov 29 '22 15:11

Marcin Doliwa


2 Answers

Recursive.

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

Defining it on the Hash class.

class Hash
  def flatten_nested; flat_map{|k, v| [k, *v.flatten_nested]} end
end
like image 190
sawa Avatar answered Dec 23 '22 09:12

sawa


With Ruby 2.1 and later you can use refinements to add a method to Hash and expose it only to the modules / classes you need.

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

In your class / module

class MyThing
  using HashRefinements

  ...

  def flatten_categories
    categories.flatten_nested
  end

  ...
end
like image 26
patkoperwas Avatar answered Dec 23 '22 08:12

patkoperwas