排序按类别和子类别无限对象的数组,最好的办法 [英] best way to sort an array of objects by category and infinite subcategory

查看:131
本文介绍了排序按类别和子类别无限对象的数组,最好的办法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个数据库,我将在下面拉着对象的数组。我想从它创建一个树形结构。

当PARENT_ID为零那么它的顶级类别。如果PARENT_ID不是nil则一个子类别值PARENT_ID的id的。

我想出了最好的解决办法是通过设置环获得顶级类别然后继续循环,直到通过我安排。最终,该表将小于500的记录,但有没有这样的保证。因此,循环一遍又一遍,似乎很愚蠢。但是,我想不出另一种方式来做到这一点。下面是一个示例数据集,它会组织方式。

  [{ID:1,名称:顶级测试1,PARENT_ID:无},
 {ID:2,名称:测试2,PARENT_ID:1},
 {ID:3,名称:测试3,PARENT_ID:1},
 {ID:4,名称:顶考4,PARENT_ID:无},
 {ID:5,名称:测试5,PARENT_ID:3},
 {ID:6,名称:试验6,PARENT_ID:4},
 {ID:7,名称:测试7,PARENT_ID:4}]
顶级测试1
  测试2
  测试3
    测试5
顶级测试2
  测试6
  测试7

对象的实际数组从DB返回。还只是测试数据。

  [#< ItemsCategory ID:2,名称:测试2,PARENT_ID:1,created_at:2014年3月4日17时58分46秒,的updated_at: 2014年3月4日17点58分46秒>中
#< ItemsCategory ID:3,名称:测试3,PARENT_ID:1,created_at:2014年3月4日17时23分23秒,的updated_at:2014年3月4日17时23分23秒> ,
#< ItemsCategory ID:5,名称:考4,PARENT_ID:3,created_at:2014年3月6日17时48分25秒,的updated_at:2014年3月6日17时48分25秒> ,
#< ItemsCategory ID:1,名称:新的测试编着,PARENT_ID:无,created_at:2014年3月4日17时57分21秒,的updated_at:2014年3月10日二十时五十分10秒&GT ]


解决方案

您可以做到这一点是这样的:

code

 高清DOIT(数据,缩进= 2)
  D = data.each_with_object({}){| H,G |政[H [:ID] = H}
  d.each {| _,H | H [:ancestor_ids] =
    (H [:top_level_category_id] D [H [:PARENT_ID]?[:ancestor_ids]:[])+ [H [:ID]}
   .values
   .sort_by {| H | H [:ancestor_ids]}
   。每个{| H |看跌期权''*((H [:ancestor_ids] .size-1)*缩进)+#{H [:名字]}
结束

演示

 数据= [
  {ID:1,名称:父测试1,PARENT_ID:无,top_level_category_id:无},
  {ID:2,名称:测试2,PARENT_ID:1,top_level_category_id:1},
  {ID:3,名称:测试3,PARENT_ID:1,top_level_category_id:1},
  {ID:4,名称:父测试4,PARENT_ID:无,top_level_category_id:无},
  {ID:5,名称:测试5,PARENT_ID:3,top_level_category_id:4},
  {ID:6,名称:试验6,PARENT_ID:4,top_level_category_id:4},
  {ID:7,名称:测试7,PARENT_ID:4,top_level_category_id:4}
]度特(数据)
父测试1
  测试2
  测试3
    测试5
父测试4
  测试6
  测试7

说明

我们需要做的是增加一个散列元素(其主要我命名:ancestor_ids ),其值是哈希的:ID 以及所有祖先的;即,我们希望下面元素添加到各自的散列

 :ancestor_ids => [1]
:ancestor_ids => [1,2]
:ancestor_ids => [1,3]
:ancestor_ids => [4]
:ancestor_ids => [1,3,5]
:ancestor_ids => [4,6]
:ancestor_ids => [4,7]

一旦我们有了这些,我们可以使用 sort_by {| H | H [:ancestor_ids]} 来把数组数据的元素以正确的顺序。 (如果您不确定如何数组中的元素是有序的,审查的阵列#< => )同样小时。[:ancestor_ids] .size 用于确定所需的缩进量显示结果的时候。

的计算是这样的*:

  D = data.each_with_object({}){| H,G |政[H [:ID] = H}
  #=> {1 => {:ID =大于1,:名称=>中的父试验1,...},
  #2 => {:ID =大于2,:名称=>中测试2,...},
  #3 => {:ID =→3,:名称=>中测试3,...},
  #4 => {:ID =→4,:名称=>中的父测试4,...},
  #5 => {:ID =→5,:名称=>中测试5,...},
  #6 => {:ID => 6,:名称=>中考6,...},
  #7 = GT; {:ID =大于7,:名称=>中测试7,...}}

我们执行这一步,可以很容易找到对应于一个记录的父数据的行。

  E = {d.each | _,H | H [:ancestor_ids] =
    (H [:top_level_category_id] D [H [:PARENT_ID]?[:ancestor_ids]:[])+ [H [:ID]}
  #=> {1 => {:ID =大于1,...,:ancestor_ids = GT; [1]},
  #2 => {:ID =大于2,...,:ancestor_ids = GT; [1,2]},
  #3 => {:ID =→3,...,:ancestor_ids = GT; [1,3]},
  #4 => {:ID =→4,...,:ancestor_ids = GT; [4]}
  #5 => {:ID =大于5,...,:ancestor_ids = GT; [1,3,5]},
  #6 => {:ID =→6,...,:ancestor_ids = GT; [4,6]},
  #7 = GT; {:ID =大于7,...,:ancestor_ids = GT; [4,7]}}

这增加了它的关键是元素:ancestor_ids 。我们不再需要钥匙,所以我们将提取值,通过对它们进行排序:ancestor_ids 并显示结果:

  F = e.values
  #=> [{:ID =大于1,...,:ancestor_ids = GT; [1]},
  #{:ID =大于2,...,:ancestor_ids = GT; [1,2]},
  #{:ID =→3,...,:ancestor_ids = GT; [1,3]},
  #{:ID =→4,...,:ancestor_ids = GT; [4]}
  #{:ID =大于5,...,:ancestor_ids = GT; [1,3,5]},
  #{:ID =→6,...,:ancestor_ids = GT; [4,6]},
  #{:ID =大于7,...,:ancestor_ids = GT; [4,7]}}G = {f.sort_by | H | H [:ancestor_ids]}
  #=> [{:ID =大于1,...,:ancestor_ids = GT; [1]},
  #{:ID =大于2,...,:ancestor_ids = GT; [1,2]},
  #{:ID =→3,...,:ancestor_ids = GT; [1,3]},
  #{:ID =大于5,...,:ancestor_ids = GT; [1,3,5]},
  #{:ID =→4,...,:ancestor_ids = GT; [4]}
  #{:ID =→6,...,:ancestor_ids = GT; [4,6]},
  #{:ID =大于7,...,:ancestor_ids = GT; [4,7]}}缩进= 2
g.each {| H |看跌期权''*((H [:ancestor_ids] .size-1)*缩进)+#{H [:名字]}
父测试1
  测试2
  测试3
    测试5
父测试4
  测试6
  测试7

分数


  • 请您需要的哈希元素,其关键是:top_level_category_id ,考虑到:PARENT_ID =>零为顶级元素?

  • 生产code会如果在电子上面的计算中,没有 D 与关键 H [:PARENT_ID] 或价值 H [:PARENT_ID] 无键:ancestor_ids

  • 这个答案依赖于假设,每个元素 ^ h 数据不是顶级的 H [:ID> H [:PARENT_ID] H [:PARENT_ID] 不是零。如果行数据不是最初由命令:ID ,它们必须是 sort_by 'ED :ID 作为第一步

*
如果您在家中尝试运行此,它应该在命令行工作,但IRB撬无法处理以点开始的持续行

I have a databases that I will be pulling the array of objects below. I want to create a tree structure from it.

When the parent_id is nil then its a top level Category. If the parent_id is not nil then it a subcategory of the id value of parent_id.

The best solution I have come up with was to loop through the set to get the top level categories then continue looping through until I have organized. Ultimately the table will be less than 500 records but there is no guarantee of that. So looping over and over seems really stupid. However, I can't think of another way to do it. Below is a sample dataset and the way it would be organized.

[{id: 1, name: "top test 1", parent_id: nil},
 {id: 2, name: "test 2", parent_id: 1},
 {id: 3, name: "test 3", parent_id: 1},
 {id: 4, name: "top test 4", parent_id: nil},
 {id: 5, name: "test 5", parent_id: 3},
 {id: 6, name: "test 6", parent_id: 4},
 {id: 7, name: "test 7", parent_id: 4}]


top test 1
  test 2
  test 3
    test 5
top test 2
  test 6
  test 7

Actual array of objects returned from the db. Still just test data.

[#<ItemsCategory id: 2, name: "test 2", parent_id: 1, created_at: "2014-03-04 17:58:46", updated_at: "2014-03-04 17:58:46">, 
#<ItemsCategory id: 3, name: "test 3", parent_id: 1, created_at: "2014-03-04 17:23:23", updated_at: "2014-03-04 17:23:23">, 
#<ItemsCategory id: 5, name: "test 4", parent_id: 3, created_at: "2014-03-06 17:48:25", updated_at: "2014-03-06 17:48:25">, 
#<ItemsCategory id: 1, name: "NEW test EDITED", parent_id: nil, created_at: "2014-03-04 17:57:21", updated_at: "2014-03-10 20:50:10">]

解决方案

You can do it like this:

Code

def doit(data, indent = 2)
  d = data.each_with_object({}) { |h,g| g[h[:id]] = h }
  d.each {|_,h| h[:ancestor_ids] =
    (h[:top_level_category_id] ? d[h[:parent_id]][:ancestor_ids] :[])+[h[:id]]}
   .values
   .sort_by { |h| h[:ancestor_ids] }
   .each { |h| puts ' '*((h[:ancestor_ids].size-1)*indent) + "#{h[:name]}" }
end

Demo

data=[
  {id: 1, name: "parent test 1", parent_id: nil, top_level_category_id: nil},
  {id: 2, name: "test 2", parent_id: 1, top_level_category_id: 1},
  {id: 3, name: "test 3", parent_id: 1, top_level_category_id: 1},
  {id: 4, name: "parent test 4", parent_id: nil, top_level_category_id: nil},
  {id: 5, name: "test 5", parent_id: 3, top_level_category_id: 4},
  {id: 6, name: "test 6", parent_id: 4, top_level_category_id: 4},
  {id: 7, name: "test 7", parent_id: 4, top_level_category_id: 4}
]

doit(data)
parent test 1
  test 2
  test 3
    test 5
parent test 4
  test 6
  test 7

Explanation

What we need to do is add another hash element (whose key I've named :ancestor_ids), whose value is an array of the hash's :id and those of all of its ancestors; i.e., we want to add the following elements to the respective hashes:

:ancestor_ids => [1]
:ancestor_ids => [1,2]
:ancestor_ids => [1,3]
:ancestor_ids => [4]
:ancestor_ids => [1,3,5]
:ancestor_ids => [4,6]
:ancestor_ids => [4,7]

Once we have these, we can use sort_by { |h| h[:ancestor_ids] } to put the elements of the array data in the proper order. (If you are uncertain how the elements of an array are ordered, review Array#<=>.) Also h[:ancestor_ids].size is used to determine the amount of indentation required when displaying the results.

The calculations go like this*:

d = data.each_with_object({}) { |h,g| g[h[:id]] = h }
  #=> {1=>{:id=>1, :name=>"parent test 1",...},
  #    2=>{:id=>2, :name=>"test 2",...},
  #    3=>{:id=>3, :name=>"test 3",...},
  #    4=>{:id=>4, :name=>"parent test 4",...},
  #    5=>{:id=>5, :name=>"test 5",...},
  #    6=>{:id=>6, :name=>"test 6",...},
  #    7=>{:id=>7, :name=>"test 7",...}} 

We perform this step to make it easy to find the rows of data that correspond to a record's parent.

e = d.each {|_,h| h[:ancestor_ids] =
    (h[:top_level_category_id] ? d[h[:parent_id]][:ancestor_ids]:[])+[h[:id]]}
  #=> {1=>{:id=>1,...,:ancestor_ids=>[1]},
  #    2=>{:id=>2,...,:ancestor_ids=>[1, 2]},
  #    3=>{:id=>3,...,:ancestor_ids=>[1, 3]},
  #    4=>{:id=>4,...,:ancestor_ids=>[4]}
  #    5=>{:id=>5,...,:ancestor_ids=>[1, 3, 5]},
  #    6=>{:id=>6,...,:ancestor_ids=>[4, 6]},
  #    7=>{:id=>7,...,:ancestor_ids=>[4, 7]}}

This adds the element whose key is :ancestor_ids. We no longer need the keys, so we will extract the values, sort them by :ancestor_ids and display the results:

f = e.values
  #=> [{:id=>1,...,:ancestor_ids=>[1]},
  #    {:id=>2,...,:ancestor_ids=>[1, 2]},
  #    {:id=>3,...,:ancestor_ids=>[1, 3]},
  #    {:id=>4,...,:ancestor_ids=>[4]}
  #    {:id=>5,...,:ancestor_ids=>[1, 3, 5]},
  #    {:id=>6,...,:ancestor_ids=>[4, 6]},
  #    {:id=>7,...,:ancestor_ids=>[4, 7]}}

g = f.sort_by { |h| h[:ancestor_ids] }
  #=> [{:id=>1,...,:ancestor_ids=>[1]},
  #    {:id=>2,...,:ancestor_ids=>[1, 2]},
  #    {:id=>3,...,:ancestor_ids=>[1, 3]},
  #    {:id=>5,...,:ancestor_ids=>[1, 3, 5]},
  #    {:id=>4,...,:ancestor_ids=>[4]}
  #    {:id=>6,...,:ancestor_ids=>[4, 6]},
  #    {:id=>7,...,:ancestor_ids=>[4, 7]}}

indent = 2
g.each { |h| puts ' '*((h[:ancestor_ids].size-1)*indent) + "#{h[:name]}" }
parent test 1
  test 2
  test 3
    test 5
parent test 4
  test 6
  test 7

Points

  • Do you need the hash element whose key is :top_level_category_id, considering that :parent_id => nil for top level elements?
  • Production code would raise an exception if, in the calculation of e above, there were no element of d with key h[:parent_id] or the value h[:parent_id] had no key :ancestor_ids.
  • This answer relies on the assumption that, for each element h of Data that is not top level, h[:id] > h[:parent_id] when h[:parent_id] is not nil. If the rows of Data are not initially ordered by :id, they must be sort_by'ed :id as a first step.

* If you try running this at home, it should work from the command line, but IRB and PRY cannot handle the continued lines that begin with a dot

这篇关于排序按类别和子类别无限对象的数组,最好的办法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆