简体   繁体   中英

Intersection of list in the old way: without sets and without in operator

As a python user, it is quite an unusual question. For once, I can not use all the magic functions and lovely build-in operators. Thus I am kind of lost.

I have 2 to 6 lists containing lists of custom objects. The objects do have a method __eq__ but it is actually not correct for this usecase. Moreover, they are loaded from a pickle file. Thus, I can not modify the object class and re-implement the method.

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], ...]
...

As stated in the title, I'm looking for the element of L1 presents in all the other lists. ie I'm looking for the sublist of objects present in the other lists of sublists.

How to I define if a list of object from L1 is the same as a list of object from 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]

Knowing those lists are quite large (thousands of elements), how can I find the intersection based on this condition?

Dummy example:

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)]]

The intersection would be those 2 lists:

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

Now this example has only 2 lists, L1 and L2. What if I have L1, L2, L3, L4, L5 and L6 and I want the elements present in ALL of them?

I'm currently trying using for loops, and an equality function:

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)

Any better way to do this? Thanks!

You can certainly shorten it, using all and 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))
]

In both the equality and the intersection the use of all and any guarantees early breaking of the iterations. There is no need to build the full lists of elt.s if you know they are not equal when you see the first mismatch.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM