【问题标题】:Ruby sort array of hashes by child-parent relationRuby 按子父关系对哈希数组进行排序
【发布时间】:2015-04-21 20:54:54
【问题描述】:

所以我们有一个哈希数组

array = [
  {id: 1, parent_id: 0},
  {id: 2, parent_id: 1},
  {id: 3, parent_id: 0},
  {id: 4, parent_id: 2}
]
target_array = []

将该数组映射/排序到以下结果的最有效和最有效的方法是什么:

target_array = [
  {id:1,children:
    [{id: 2, children: [
      {id:4, children:[]}]}]},
  {id: 3, children:[]}  
]

p.s.我能做的最多就是为每个项目迭代整个事情,并从已经映射到 target_array 的数组哈希中排除。

【问题讨论】:

    标签: ruby iteration


    【解决方案1】:

    你可以用递归解决这个问题:

    @array = [
      {id: 1, parent_id: 0},
      {id: 2, parent_id: 1},
      {id: 3, parent_id: 0},
      {id: 4, parent_id: 2}
    ]
    
    
    def build_hierarchy target_array, n
        @array.select { |h| h[:parent_id] == n }.each do |h|
          target_array << {id: h[:id], children: build_hierarchy([], h[:id])}
        end
        target_array
    end
    
    
    build_hierarchy [], 0
    

    输出:

    => [{"id"=>1, "children"=>[{"id"=>2, "children"=>[{"id"=>4, "children"=>[]}]}]}, {"id"=>3, "children"=>[]}] 
    

    这个红宝石小提琴http://rubyfiddle.com/riddles/9b643中的活生生的例子

    【讨论】:

    • 我也只是尝试通过哈希解决。但我认为你的方法更干净 1+
    【解决方案2】:

    这是我尝试使用 Hash

    的方式
    array = [
      {id: 1, parent_id: 0},
      {id: 2, parent_id: 1},
      {id: 3, parent_id: 0},
      {id: 4, parent_id: 2}
    ]
    
      target_hash = Hash.new { |h,k| h[k] = { id: nil, children: [ ] } }
    
      array.each do |n|
          id, parent_id = n.values_at(:id, :parent_id)
          target_hash[id][:id] = n[:id]
          target_hash[parent_id][:children].push(target_hash[id])  
      end
     puts target_hash[0]
    

    输出:

    {:id=>nil, :children=>[{:id=>1, :children=>[{:id=>2, :children=>[{:id=>4, :children=>[]}]}]}, {:id=>3, :children=>[]}]}
    

    【讨论】:

      【解决方案3】:

      我认为最好的最多有 O(nlog(n)) 时间复杂度。我给我的非散列一个:

      array = [
        {id: 1, parent_id: 0},
        {id: 2, parent_id: 1},
        {id: 3, parent_id: 0},
        {id: 4, parent_id: 2}
      ]
      
      # This takes O(nlog(n)).
      array.sort! do |a, b|
          k = (b[:parent_id] <=> b[:parent_id])
          k == 0 ? b[:id] <=> a[:id] : k
      end
      
      # This takes O(n)
      target_array = array.map do |node|
          { id: node[:id], children: [] }
      end
      
      # This takes O(nlog(n))
      target_array.each_with_index do |node, index|
          parent = target_array[index + 1...target_array.size].bsearch do |target_node|
              target_node[:id] == array[index][:parent_id]
          end
          if parent
              parent[:children] << node
              target_array[index] = nil
          end
      end
      
      # O(n)
      target_array.reverse.compact
      # =>
      # [{:id => 1, :children =>[{:id=>2,:children=> [ {:id=>4, 
      # :children=>[]}]}]},
      # {:id=>3, :children=>[]} ] 
      

      所以我的一般使用 O(nlog(n))。

      顺便说一句,当我简单地测试现有的解决方案时,我发现 Gagan Gami 的效率最高(略领先于我的),我相信它也是 O(nlog(n)),尽管并不明显。但目前公认的解决方案需要 O(n^2) 时间。

      【讨论】:

        【解决方案4】:

        我会使用递归,但以下可以很容易地转换为非递归方法。

        首先构造一个将父母与子女联系起来的哈希 (p2c)。为此,请使用Hash#update(又名merge!)的形式,它使用一个块来确定合并的两个哈希中存在的键的值:

        @p2c = array.each_with_object({}) { |g,h|
          h.update(g[:parent_id]=>[g[:id]]) { |_,ov,nv| ov+nv } }
          #=> {0=>[1, 3], 1=>[2], 2=>[4]} 
        

        还有许多其他方法可以构造此哈希。这是另一个:

        @p2c = Hash[array.group_by { |h| h[:parent_id] }
                         .map { |k,v| [k, v.map { |g| g[:id] }] }]
        

        现在构造一个递归方法,其唯一参数是父级:

        def family_tree(p=0)
          return [{ id: p, children: [] }] unless @p2c.key?(p)
          @p2c[p].each_with_object([]) { |c,a|
            a << { id:c, children: family_tree(c) } }
        end
        

        我们得到:

        family_tree
          #=> [ { :id=>1, :children=>
          #               [
          #                { :id=>2, :children=>
          #                          [
          #                            { :id=>4, :children=>[] }
          #                          ]
          #                }
          #              ]
          #    },
          #    { :id=>3, :children=>[] }
          #  ] 
        

        最初构造哈希 @p2c 应该会非常高效。

        【讨论】:

          猜你喜欢
          • 2016-11-16
          • 1970-01-01
          • 1970-01-01
          • 2014-03-05
          • 1970-01-01
          • 1970-01-01
          • 2011-02-02
          • 1970-01-01
          相关资源
          最近更新 更多