【问题标题】:How to convert path data to adjacency list如何将路径数据转换为邻接表
【发布时间】:2019-06-11 03:20:58
【问题描述】:

我正在设置一个 Rails“从 csv 导入”任务,我遇到了以路径形式存在的部门数据(在 db 中)。我希望它是邻接列表。

我有:

ID, NAME, PATH
---------
1,Valve,000
2,Steam,000.000
3,Sales,000.000.000
4,Developers,000.000.112
7,Designers,000.000.112.000
8,Game Designers,000.000.112.000.000
9,UI Designers,000.000.112.000.002
10,Web Designers,000.000.112.000.001
11,3D Designers,000.000.112.000.003
12,Accounting managers,000.000.114.000
13,Accounting topmanagers,000.000.114.000.000

我想要的:

ID, NAME, PATH, PARENT_ID
---------
1,Valve,000, nil
2,Steam,000.000, 1
3,Sales,000.000.000, 2
4,Developers,000.000.112, 2
7,Designers,000.000.112.000, 4
8,Game Designers,000.000.112.000.000, 7
9,UI Designers,000.000.112.000.002, 7
10,Web Designers,000.000.112.000.001, 7
11,3D Designers,000.000.112.000.003, 7
12,Accounting managers,000.000.114.000, 322
13,Accounting topmanagers,000.000.114.000.000, 12

【问题讨论】:

  • 那么,您只想将前一行的 ID 附加到每一行吗?你能展示一下你的尝试吗?
  • @maxpleaner 问题是路径不包含标识符,只有序列号。
  • 应该'322''2'
  • @CarySwoveland 不,他们不在销售部门(路径为 000.000.114),这是另一个部门。
  • 请解释'322'在底层图形方面的含义。

标签: mysql ruby graph hierarchical-data adjacency-list


【解决方案1】:

该字符串似乎描述了一个有向树,但会计经理除外,

'12,Accounting managers,000.000.114.000'

似乎没有老板。因此我添加了

'14,Accounting big cheese,000.000.114'

这是数据。

data =<<-_
ID, NAME, PATH
---------
1,Valve,000
2,Steam,000.000
3,Sales,000.000.000
4,Developers,000.000.112
7,Designers,000.000.112.000
8,Game Designers,000.000.112.000.000
9,UI Designers,000.000.112.000.002
10,Web Designers,000.000.112.000.001
11,3D Designers,000.000.112.000.003
14,Accounting big cheese,000.000.114
12,Accounting managers,000.000.114.000
13,Accounting topmanagers,000.000.114.000.000
_

我们可以使用split("\n")将这个字符串转换为行数组,然后确定每个节点的父级如下。

r1, r2, *rest = data.split("\n")
str = [
  r1,
  r2,
  rest.map do |s|
    parent_match = s[/(?:\d{3}\.)*\d{3}(?=\.\d{3})/]
    parent = arr.find { |ss| parent_match == ss[/(?:\d{3}\.)*\d{3}/] }
    parent.nil? ? "#{s}, nil" : "#{s}, #{ parent[/\d+/] }" 
    end
].join("\n")

puts str 
ID, NAME, PATH
---------
1,Valve,000, nil
2,Steam,000.000, 1
3,Sales,000.000.000, 2
4,Developers,000.000.112, 2
7,Designers,000.000.112.000, 4
8,Game Designers,000.000.112.000.000, 7
9,UI Designers,000.000.112.000.002, 7
10,Web Designers,000.000.112.000.001, 7
11,3D Designers,000.000.112.000.003, 7
14,Accounting big cheese,000.000.114, 2
12,Accounting managers,000.000.114.000, 14
13,Accounting topmanagers,000.000.114.000.000, 12

假设在map的块中

s = '8,Game Designers,000.000.112.000.000'

然后

parent_match = s[/(?:\d{3}\.)*\d{3}(?=\.\d{3})/]
  #=> "000.000.112.000" 

parent_match 是由s 中的句点分隔的所有三位数字组成的字符串,除了最后一个句点后跟最后一个三位数字。正则表达式为“匹配零个或多个 3 位数字组,后跟一个句点,后跟 3 位数字,前提是此匹配后紧跟一个句点和 3 位数字 ((?=\.\d{3})),即正向预测 em>)。

然后我们遍历rest 寻找以parent_match 结尾的元素:

parent = rest.find { |ss| parent_match == ss[/(?:\d{3}\.)*\d{3}/] }
  #=> "7,Designers,000.000.112.000"

正则表达式 /(?:\d{3}\.)*\d{3}/ 表示“匹配零个或多个 3 位数字组,后跟句点,后跟 3 位数字”。

在下一行:

parent.nil?
  #=> false

所以块返回

"#{s}, #{ parent[/\d+/] }" 
  #=> "8,Game Designers,000.000.112.000.000, 7"

parent[/\d+/] 仅提取parent 开头的数字字符。

如果我没有添加该行

14,Accounting big cheese,000.000.114

以下行 ('12,Accounting ...') 将结束,', nil'

【讨论】:

  • 8,9,10,11 的 parent_id 与 7 相同。我猜我的错,我的数据不够清晰。
  • 我已经更新了问题。调整。 list - 只是带有 id 和 parent_id 的常规层次结构。
猜你喜欢
  • 2022-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多