【问题标题】:Merge Hashes and key gets both, old and new values合并哈希和键同时获取旧值和新值
【发布时间】:2015-09-26 14:26:48
【问题描述】:

想象一下我有一个这样的数组

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

我希望我的所有数组都创建一个散列,其中的键包含我的数组中的不同类。 它们的值将是每个类的实际元素。

所以它看起来像这样:

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

我想在不使用 flatten 的情况下解决整个问题,但这样做是递归的。 扁平化解决方案可能如下所示:

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

对于那些想知道为什么我不想使用 flatten 的人:我仍然无法完全理解如何实现递归方法,因此这是一个让我更好理解的问题。

我想我必须以某种方式实现与块的合并,但我无法找出合适的块。 merge(x.deep_collect_by_elem_type_as_hash(){|k,v1,v2| help}

【问题讨论】:

    标签: arrays ruby recursion hash merge


    【解决方案1】:

    你可以这样做:

    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}]} 
    

    你也可以写:

    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}]} 
    

    【讨论】:

    • 喜欢它的紧凑程度:) 一定要爱上 ruby​​
    【解决方案2】:

    我们开始:

    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
    

    如果您需要打开和扩展数组,您可以按照以下方式进行操作:

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

    【讨论】:

    • 这是做什么的?资源[k] ||= []
    • 这是一个惰性初始化。如果未定义 res[k],您阅读它的方式是 res[k] = []。所以基本上如果hash res中没有key k,就会把(k,[])放到hash中
    • 你可以用 res[k] = [] 代替它,除非 res.key?(k) ,但我写它的方式是惯用的 ruby​​
    猜你喜欢
    • 2017-03-16
    • 2015-11-12
    • 1970-01-01
    • 2013-02-24
    • 2021-12-30
    • 2015-06-13
    • 2018-06-10
    • 1970-01-01
    相关资源
    最近更新 更多