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 построчно, требуйте непустоты обоих пересечений и затем объединяйте их. Предпочитайте прямые проверки истинности множеств и выбирайте либо операции над множествами, либо списковые включения — что понятнее. Ключ к правильному и поддерживаемому решению — сохранять выравнивание итерации.