1

I have an array which looks like this:

array = [[:foo, :bar], [:foo, :baz], [:baz, {a: 1, b: 2}], [:baz, {c: 1, d:2}]]

and I need to turn it into a hash which looks like this:

{:foo =>[:bar, :baz], :baz => {a: 1, b: 2, c: 1, d: 2}}

This is the code I have so far:

def flatten(array)
  h = {}
  array.each_with_object({}) do |(k, v), memo|
    if v.is_a?(Hash)
      memo[k] = h.merge!(v)
    else
      # What goes here?
    end
  end
end

When used like so:

flatten(array)

outputs:

{baz => {:a => 1, :b => 2, :c => 1, :d => 2}}

May someone please point me in the right direction? Help appreciated.

2
  • Wow that's such an inconsistent transformation. You perform different unification operations depending on the types. What if array = [[:foo, {:a => 1}], [:foo, :bar]]? Commented Jul 23, 2015 at 19:19
  • Your sample code does not compile: for example, list and memo are undefined. Please paste the code you actually tested. Commented Jul 23, 2015 at 19:48

3 Answers 3

1
def convert(arr)
  arr.each_with_object({}) do |a,h|
    h[a.first] =        
      case a.last
      when Hash
        (h[a.first] || {}).update(a.last)
      else
        (h[a.first] || []) << a.last
      end
  end
end

convert array
  #=> {:foo=>[:bar, :baz], :baz=>{:a=>1, :b=>2, :c=>1, :d=>2}}
Sign up to request clarification or add additional context in comments.

Comments

0
Hash[ array.group_by(&:first).map{ |k,a| [k,a.map(&:last)] } ]

3 Comments

you were right @kirill. i removed my answer actually. bcoz my approach was changed and becomes similar to Cary. but thanks.. i didnt notice that difference... Thanks.
Output of this answer is not same as the one expected by OP
@WandMaker, I figured out after posting. And that was mentioned already (comment is removed).
0

Here is my attempt at solving this problem. I have to make assumption that in the input array, entries like the ones similar to :baz will always be paired with Hash objects. The solution will not work if you have one :baz with a symbol and another with hash.

array = [[:foo, :bar], [:foo, :baz], [:baz, {a: 1, b: 2}], [:baz, {c: 1, d:2}]]

h = Hash.new
array.each do |n1, n2|
    if n2.class == Hash
      h[n1] = (h[n1] || {}).merge(n2) 
    else
      h[n1] = (h[n1] || []) << n2
    end
end
p h

Output

{:foo=>[:bar, :baz], :baz=>{:a=>1, :b=>2, :c=>1, :d=>2}}
[Finished in 0.1s]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.