2025, Dec 05 03:01
Как пересекать двумерные списки в Python построчно с выравниванием через zip
Как пересекать значения между двумерными списками в Python построчно: обход B и C через zip, требуем оба пересечения, показаны код и корректный результат.
При сопоставлении значений между несколькими списками важно совпадение строк. Классическая ошибка — перебирать все возможные пары строк, что незаметно нарушает ограничение «одна и та же строка в B и C». Ниже — компактное руководство о том, как пересекать три двумерных списка построчно и забирать только те значения, которые удовлетворяют условию для B и C на одном и том же индексе.
Исходные данные
У нас есть три двумерных списка. Задача — для каждой строки первого списка находить значения, которые также встречаются в соответствующих строках второго и третьего списков, при этом B и C сопоставляются по индексу. В результат должны попадать только те строки, где оба пересечения не пусты.
data_a = [
[11, 27, 41, 42],
[7, 26, 34, 36],
[8, 22, 24, 38, 42]
]
data_b = [
[11, 42],
[11, 32],
[7, 14],
[11, 17, 21],
[21, 38],
[11, 42, 45]
]
data_c = [
[15, 16, 21, 27, 38, 44],
[34, 39, 42],
[20, 21, 35, 36, 49],
[2, 12, 22, 24, 30],
[21, 22, 27, 31, 42],
[1, 5, 8, 27, 32, 38]
]
Наивная попытка и в чем ошибка
Прямолинейный, но неверный подход — сделать тройной вложенный цикл, пересекать каждую строку A с каждой строкой B и каждой строкой C, а затем объединять результаты при любом совпадении. Так ломается ограничение «та же строка»: каждая строка B комбинируется с каждой строкой C.
hits = []
for row_x in data_a:
for row_y in data_b:
for row_z in data_c:
s_x = set(row_x)
s_y = set(row_y)
s_z = set(row_z)
combo = (s_x & s_y) | (s_x & s_z)
if len(combo) > 0:
hits.append(list(combo))
# Это собирает совпадения, где A пересекается с B или C по всем парам строк,
# а не только по выровненным строкам, что нам не подходит.
Почему это не работает
Требование таково: если A находит совпадение с B в строке k, то оно должно быть и в строке k списка C. Значит, B и C нужно обходить синхронно по индексам. Вложенные циклы выше попарно сочетают каждую строку B с каждой строкой C, игнорируя выравнивание строк. Есть и тонкость: корректный результат требует совпадений и в B, и в C, а не только в одном из них, поэтому простого объединения пересечений и проверки на непустоту недостаточно. Наконец, вызывать len для множества не нужно — достаточно проверки на истинность.
Решение: итерировать B и C вместе и требовать оба пересечения
Чистый способ сохранить выравнивание строк — проходить по B и C одновременно с помощью zip. Для каждой строки A вычисляйте пересечения с выровненными строками B и C, убеждайтесь, что оба непусты, и затем объединяйте их.
results = []
for row_a in data_a:
for row_b, row_c in zip(data_b, data_c):
s_a = set(row_a)
inter_b = s_a.intersection(row_b)
inter_c = s_a.intersection(row_c)
if inter_b and inter_c:
results.append(list(inter_b | inter_c))
print(results)
Результат будет таким:
[[27, 42, 11], [42, 11], [27, 42, 11], [36, 7], [42, 38], [42, 38, 22], [8, 42, 38]]
Как отмечалось ранее, в изначально заявленном ожидаемом выводе была лишняя скобка и пропущено [36, 7]. Исправленный результат показан выше.
Замечание о размерности
Несмотря на формулировку «3d list», A, B и C — это двумерные списки. Логика сопоставления работает построчно в каждом из них, а строки B и C выравниваются по индексу.
Дополнительные детали реализации
При проверке пустоты пересечения идиоматично и эффективно использовать множество прямо в условии — вызывать len не требуется. Пересечение можно считать и оператором &, и методом intersection; в данном контексте они эквивалентны. При необходимости пересечение двух списков без множеств можно записать через списковое включение вроде [x for x in [11, 27, 41, 42] if x in [11, 42]], что даст [11, 42].
Почему это важно
Ошибки с выравниванием строк коварны в конвейерах обработки данных. Вложенные циклы, игнорирующие индексные ограничения, часто выглядят рабочими, но подмешивают в результат недопустимые комбинации. Использование zip закрепляет требуемую семантику парного сопоставления и делает условие явным в коде, снижая неоднозначность и число ошибок.
Итоги
Чтобы корректно сопоставлять значения между несколькими двумерными списками при ограничении равенства строк, итерируйте выровненные структуры вместе, пересекайте с A построчно, требуйте непустоты обоих пересечений и затем объединяйте их. Предпочитайте прямые проверки истинности множеств и выбирайте либо операции над множествами, либо списковые включения — что понятнее. Ключ к правильному и поддерживаемому решению — сохранять выравнивание итерации.