Reputation: 306
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
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
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