Начнем с таблицы данных employees
с самоссылками:
id name manager_id
1 Djan Seriy Anaplian
2 Fal 'Ngeestra
3 Turminder Xuss 1 ---> Djan Seriy Anaplian
4 Jase 2 ---> Fal 'Ngeestra
Как мы можем получить другую запись?
Листы
Как и многие другие вопросы в Excel, Numbers, Calc или Sheets, давайте решим их, добавив столбец с формулой INDEX и MATCH:
# 1. find row number of the matching record
=match(C2, A:A, 0)
# 2. get value from the other record
=index(B:B, match(C2, A:A, 0))
# 3. handle errors
=iferror(index(B:B, match(C2, A:A, 0)), "")
Вы можете опробовать этот пример в Sheets:
SQL
Практически во всех языках запросов к базам данных соединения с самой таблицей работают точно так же, как соединения между таблицами:
select
e.name employee,
m.name manager
from employees e
left join employees m on e.manager_id = m.id
Попробуйте в SQL Fiddle:
Python
Чтобы представить «нормальную форму» наших данных в Python, давайте выберем словарь:
employees = {
1: {'name': 'Djan Seriy Anaplian'},
2: {'name': 'Fal 'Ngeestra'},
3: {'name': 'Turminder Xuss', 'manager_id': 1},
4: {'name': 'Jase', 'manager_id': 2},
}
Мы хотим изменить его на список вложенных словарей, заменив каждый указатель manager_id
на живой объект manager
, чтобы дать себе наибольшую свободу для исследования. Используя императивный процедурный стиль кода с оператором моржа := и dict.pop(), это может выглядеть следующим образом:
for em in employees.values():
if manager_id := em.pop('manager_id', None):
em['manager'] = employees[manager_id]
employees = list(employees.values())
employees[0]['short'] = 'Anaplian'
employees[1]['short'] = 'Fal'
Этот пример живет на Repl.it. Будет ли он работать для более глубокой иерархии управления? Сломается ли он для циклической структуры?
Дайте мне знать, если вы хотите увидеть другие стили кода в Python, функциональные, как JS ниже, или FRP, как Sheets выше (с Pandas).
JavaScript / TypeScript
Мы можем начать с точно такого же объекта employees
, как в примере Python, но на этот раз мы выбираем более дружественный для команды подход, вдохновленный функциональным стилем программирования, который позволяет избежать мутации и побочных эффектов, поскольку вложенные объекты могут быть использованы в других частях проекта. Мы также хотим избежать слишком большого количества уровней вложенности, чтобы сохранить простоту, поэтому мы заменим manager_id
необязательной неизменяемой строкой managerName
:
const employeesWithManager = Object.values(employees)
.map(({name, manager_id}) => ({
name,
...(manager_id && {
managerName: employees[manager_id].name
}),
}))
Вы можете поиграть с версией TypeScript на TS Playground или запустить пример JavaScript прямо в консоли браузера:
Заметили ли вы, как мы можем использовать синтаксис распространения в объектном литерале ({...expr}
) с более сложным выражением, а не просто с именем переменной? Можете ли вы рефакторить код, чтобы использовать явную переменную в этом месте? Какая версия более читабельна для вас и для ваших коллег по проекту?
👋 Привет, я Питер Хозак, он же Aprillion. Есть ли у вас какие-либо последующие или похожие вопросы? Давайте обсудим их в комментариях ниже или в Twitter.