Matthew
Matthew

Reputation: 306

How to exclude an object from a list in Python while looping

I'm writing a program in which I loop through a list of objects. Inside that loop is a second loop, which loops through all the objects except the current object from the first loop. This repeats several times:

for obj1 in obj_list:
    for obj2 in (obj_list except obj1):
        for obj3 in (obj_list except obj1 and obj2):
            ...

My actual code does some stuff in between the loops, so I can't just use permutations() from itertools or something similar. I could implement it like this:

for i1 in range(len(obj_list)):
    obj1 = obj_list[i1]
    for i2 in range(len(obj_list)-1):
        obj2 = (obj_list[:i1] + obj_list[i1 + 1:])[i2]
        ...

However, this makes for cluttered code and becomes very messy as I try to exclude multiple objects. Is there a concise way to implement this idea, something similar to the first code block, that doesn't end up modifying the original list? Note that there are no repeated objects in my list, so a method that does not allow for them is fine.

Upvotes: 2

Views: 3935

Answers (2)

Dair
Dair

Reputation: 16240

They have equivalent Python code to the permutation function, you can modify it to accept a function:

def permutations(iterable, func, r=None):
    # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
    # permutations(range(3)) --> 012 021 102 120 201 210
    pool = tuple(iterable)
    n = len(pool)
    r = n if r is None else r
    if r > n:
        return
    indices = list(range(n))
    cycles = list(range(n, n-r, -1))
    yield tuple(pool[i] for i in indices[:r])
    while n:
        func()
        for i in reversed(range(r)):
            cycles[i] -= 1
            if cycles[i] == 0:
                indices[i:] = indices[i+1:] + indices[i:i+1]
                cycles[i] = n - i
            else:
                j = cycles[i]
                indices[i], indices[-j] = indices[-j], indices[i]
                yield tuple(pool[i] for i in indices[:r])
                break
        else:
            return

f = lambda: print('LOL')

list(permutations([1,2,3,4], f))

For every permutation, func is called, and "LOL" is printed. Output:

LOL
LOL
LOL
LOL
LOL
LOL
LOL
LOL
LOL
LOL

Upvotes: 1

Patrick Collins
Patrick Collins

Reputation: 10594

Consider this:

for obj1 in obj_list:
    for obj2 in (obj for obj in obj_list if obj != obj1):
        for obj3 in (obj for obj in obj_list if obj not in (obj1, obj2)):
            # ....

You can make a more general-purpose generator to do what you want like this:

def exclusion_generator(base_list, to_excludes):
    for item in base_list:
        if item not in to_excludes:
            yield item

and use it like this:

for obj1 in objs:
    for obj2 in exclusion_generator(objs, (obj1,)):
        for obj3 in exclusion_generator(objs, (obj1, obj2)):
            # ....

Upvotes: 4

Related Questions