Merging hashes and keys gets both old and new values

Imagine I have an array like this

array = [4,"hello",[[3],:d,7,[:a,"seven"]]]



class Array
  def deep_collect_by_elem_type_as_hash()
    e = {}
    self.each(){|x|
      if x.is_a?(Array)
        e.merge(x.deep_collect_by_elem_type_as_hash)
      end
      if !x.is_a?(Array)
        if e.has_key?(x.class)
          e[x.class]<<x
        else
          e[x.class] = [x]
        end
      end
    }
    return e
  end

      

I want all of my arrays to create a hash that has keys containing the different classes that are in my array. Their values โ€‹โ€‹will be valid elements for each class.

So it will look like this:

{Fixnum=>[4, 3, 7], String=>["hello", "seven"], Symbol=>[:d, :a]}

      

I want to solve all of this without using anti-aliasing, but doing it recruitingly. A flat solution might look like this:

def deep_collect_by_elem_type_as_hash1()
    e = {}
    flat= self.flatten()
    flat.each(){|x|
      if e.has_key?(x.class)
        e[x.class]<<x
      else
        e[x.class] = [x]
      end
    }
    return e
  end

      

For those wondering why I don't want to use anti-aliasing: I still have problems fully understanding how to implement recursive methods and so this is a question that will help me understand better.

I think I somehow need to implement a merge with a block, but I can't figure out the correct block. merge(x.deep_collect_by_elem_type_as_hash(){|k,v1,v2| help}

+3


source to share


2 answers


Here we go:

a = [4,"hello",[[3],:d,7,[:a,"seven"]]]

def stuff(a)
  res = {}
  a.each do |e|
    if e.is_a?(Array)
      stuff(e).each do |k,v|
        res[k] ||= []
        v.each {|x| res[k] << x}
      end
    else
      k = e.class
      res[k] ||= []
      res[k] << e
    end
  end
  res
end

puts stuff(a).inspect

      



if you need to open and expand an array, you can do something line by line:

class Array
  def stuff(a = self)
  ...
  end
end

      

+2


source


You can do it like this:

def group_by_class(arr, h = Hash.new { |h,k| h[k] = [] })
  arr.each { |e| e.is_a?(Array) ? group_by_class(e,h) : h[e.class] << e }
  h
end

array = [4,"hello",[[3],:d,7,[:a,"seven"]]]
group_by_class(array)
  #=> {Fixnum=>[4, 3, 7], String=>["hello", "seven"], Symbol=>[:d, :a]}

array = [4,"hello",[[3],:d,7,[:a,"seven",["b",9,[:e,["cat", {a: 0}, 5]]]]]]
group_by_class(array)
  #=> {Fixnum=>[4, 3, 7, 9, 5], String=>["hello", "seven", "b", "cat"],
  #    Symbol=>[:d, :a, :e], Hash=>[{:a=>0}]} 

      



You can also write:

def group_by_class(arr)
  arr.each { |e| e.is_a?(Array) ? group_by_class(e) : @h[e.class] << e }
end

@h = Hash.new { |h,k| h[k] = [] }
group_by_class(array)
@h
  #=> {Fixnum=>[4, 3, 7, 9, 5], String=>["hello", "seven", "b", "cat"],
  #    Symbol=>[:d, :a, :e], Hash=>[{:a=>0}]} 

      

+1


source







All Articles