Как преобразовать данные пути в список смежности - PullRequest
0 голосов
/ 11 июня 2019

Я настраиваю задачу rails "import from 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

1 Ответ

1 голос
/ 11 июня 2019

Строка, по-видимому, описывает целевое дерево, за исключением менеджеров по учету, у

'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})) являются положительным прогнозом * 1030».*).

Затем мы перебираем 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'.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...