Building off of what John already has, we can constrain the permutations as you described by removing the constrained types from the types list before calculating permutations. Then you could insert the types back into each permutation as defined by the constraint. The following example script would return the permutations with the constraint: "ids 1 and 2 have to always be type a for all combos". Feel free to remove the print statements.
from itertools import permutations
# these define which types must be located at the given id (index + 1)
constraints = [
{'id': 1, 'type': "a"},
{'id': 2, 'type': "a"}
]
# this is the list of types to permute
typeset = [
{'id': 1, 'type': "a"},
{'id': 2, 'type': "a"},
{'id': 3, 'type': "b"},
{'id': 4, 'type': "b"},
{'id': 5, 'type': "a"}
]
# we create lists of types to permute and remove the ones that are constrained
types_to_permute = [d["type"] for d in typeset]
constraint_types = [d["type"] for d in constraints]
for constraint_type in constraint_types:
types_to_permute.remove(constraint_type)
print(types_to_permute)
# we calculate the permutations for the unconstrained types
permutations = list(permutations(types_to_permute, r=None))
permutations = [list(permutation) for permutation in permutations]
print(permutations)
# we insert the constrained types in their given locations
for permutation in permutations:
for constraint in constraints:
permutation.insert(constraint["id"] - 1, constraint["type"])
print(permutations)
# we reconstruct the permutations in the orignal format (list of dictionaries)
final_permutations = []
for permutation in permutations:
final_permutation = []
for index, type_object in enumerate(permutation):
final_permutation.append({"id": index + 1, "type": type_object})
final_permutations.append(final_permutation)
print(final_permutations)
The final permutations would be:
[
[
{'id': 1, 'type': 'a'},
{'id': 2, 'type': 'a'},
{'id': 3, 'type': 'b'},
{'id': 4, 'type': 'b'},
{'id': 5, 'type': 'a'}],
[
{'id': 1, 'type': 'a'},
{'id': 2, 'type': 'a'},
{'id': 3, 'type': 'b'},
{'id': 4, 'type': 'a'},
{'id': 5, 'type': 'b'}],
[
{'id': 1, 'type': 'a'},
{'id': 2, 'type': 'a'},
{'id': 3, 'type': 'b'},
{'id': 4, 'type': 'b'},
{'id': 5, 'type': 'a'}],
[
{'id': 1, 'type': 'a'},
{'id': 2, 'type': 'a'},
{'id': 3, 'type': 'b'},
{'id': 4, 'type': 'a'},
{'id': 5, 'type': 'b'}],
[
{'id': 1, 'type': 'a'},
{'id': 2, 'type': 'a'},
{'id': 3, 'type': 'a'},
{'id': 4, 'type': 'b'},
{'id': 5, 'type': 'b'}],
[
{'id': 1, 'type': 'a'},
{'id': 2, 'type': 'a'},
{'id': 3, 'type': 'a'},
{'id': 4, 'type': 'b'},
{'id': 5, 'type': 'b'}]]