我正在设置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
答案 0 :(得分: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})
),它们是正向超前)。
然后我们遍历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'
。