Пересечение списка по-старому: без множеств и без оператора - PullRequest
0 голосов
/ 29 августа 2018

Для пользователя Python это довольно необычный вопрос. На этот раз я не могу использовать все магические функции и прекрасные встроенные операторы. Таким образом, я как бы потерялся.

У меня есть от 2 до 6 списков, содержащих списки пользовательских объектов. У объектов есть метод __eq__, но он на самом деле не подходит для этого варианта использования. Более того, они загружаются из файла рассола. Таким образом, я не могу изменить класс объекта и повторно реализовать метод.

L1 = [[Obj1_1, Obj1_2, Obj1_3], [Obj2_1, Obj2_2, Obj2_3], ...]
L2 = [[Obj1_12, Obj1_21, Obj1_33], [Obj2_1, Obj2_2, Obj2_3], ...]
...

Как указано в заголовке, я ищу элемент L1, представленный во всех остальных списках. то есть я ищу подсписок объектов, присутствующих в других списках подсписков.

Как определить, совпадает ли список объектов из L1 со списком объектов из L2:

List_of_Obj_in_L1 == List_of_Obj_in_L12 and [elt.s for elt in List_of_Obj_in_L1] == [elt.s for elt in List_of_Obj_in_L2]

Зная, что эти списки достаточно велики (тысячи элементов), как я могу найти пересечение на основе этого условия?

Пустой пример:

class Dummy:
    def __init__(self, f, s):
        self.f = f
        self.s = s

    def __eq__(self, D):
         return self.f == D.f

    def __ne__(self, D):
         return not self.__eq__(self, D)

L1 = [[Dummy(f, 0) for f in  (20, 30, 20, 50)], [Dummy(f, 0) for f in  (20, 30, 20, 40)], [Dummy(f, k) for k, f in  enumerate((20, 30, 20, 50))], [Dummy(f, 10) for f in  (20, 50)]]

L2 = [[Dummy(f, 0) for f in  (20, 20, 20, 50)], [Dummy(f, 0) for f in  (10, 10, 10, 10)], [Dummy(f, k) for k, f in  enumerate((20, 30, 20, 50))], [Dummy(f, 10) for f in  (20, 50)]]

Пересечение будет этими двумя списками:

Intersect = [[Dummy(f, k) for k, f in  enumerate((20, 30, 20, 50))], [Dummy(f, 0) for f in  (20, 50)]]

Теперь в этом примере есть только 2 списка, L1 и L2. Что если у меня есть L1, L2, L3, L4, L5 и L6, и я хочу, чтобы элементы присутствовали во ВСЕХ из них?

В настоящее время я пытаюсь использовать циклы for и функцию равенства:

def equality(L_dummy1, L_dummy2):
    if L_dummy1 == L_dummy2 and [elt.s for elt in L.dummy1] == [elt.s for elt in L.dummy2]:
        return True
    else:
        return False

intersection = list()
for elt in L1:

    in_L2  = False
    for elt2 in L2:
        if equality(elt, elt2):
            in_L2 = True

    in_L3 = False
    for elt2 in L3:
        if equality(elt, elt2):
            in_L3 = True

    if in_L2 and in_L3:
        intersection.append(elt)

Есть ли лучший способ сделать это? Спасибо!

1 Ответ

0 голосов
/ 29 августа 2018

Вы, конечно, можете сократить его, используя all и any:

def equality(L_dummy1, L_dummy2):
    return  L_dummy1 == L_dummy2 and \
            all(elt1.s==elt2.s for elt1, elt2 in zip(L.dummy1, L.dummy2))

intersection = [
    elt for elt in L1 if all(any(equality(elt, x) for x in l) for l in (L2, L3))
]

И в equality, и в пересечении использование all и any гарантирует раннее прерывание итераций. Нет необходимости создавать полные списки elt.s, если вы знаете, что они не равны, когда вы видите первое несоответствие.

...