-1

before I ask my question I wanted to let y'all know that I am a beginner coder and I appreciate all inputs so thanks in advance for your help.

Assume I have the following object:

set: [
       {'id': 1
        'type': a
       },

       {'id': 2
        'type': a
       },

       {'id': 3
        'type': b
       },

       {'id': 4
        'type': b
       },

       {'id': 5
        'type': a
       }
]

How could I use itertools.permutations to calculate (and eventually make copies of) all combinations of the 'type' key? i.e. have a set in which ids 3 and 5 have type b, the rest a, a set in which ids 2 and 5 have b and the rest a, etc.

Furthermore, is it possible calculate combinations given certain conditions (for example, ids 1 and 2 have to always be type a for all combos)?

Thank you all in advance

wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • 3
    what is your desired output? And do you mean `set_list = [ {'id...` instead of `set: [ {'id`? – Epsi95 Jul 22 '21 at 04:20
  • 1
    So, are you looking for "aaaaa", "aaaab", "aaaba", "aaabb", and so on? There would be 32 such combos, and 8 if only 3 spots very. How large will your sets be? – Tim Roberts Jul 22 '21 at 04:22
  • 3
    You can not have a set of dictionaries. – Klaus D. Jul 22 '21 at 04:29
  • 1
    Welcome to Stack Overflow! Please take the [tour] and read [ask]. I want to answer your question, but it's unclear. Firstly, the dict items are missing commas, which causes a SyntaxError. Once you fix that, `a` and `b` are not defined. Then, it's not really a Python object, it's an [annotation](https://docs.python.org/3/glossary.html#term-variable-annotation) of the variable name `set` as that list. Lastly, what's your desired output? Please [edit] to clarify. – wjandrea Jul 22 '21 at 05:01
  • You can't put dicts in a set cause they're mutable. So this might be helpful: [What would a “frozen dict” be?](https://stackoverflow.com/q/2703599/4518341) – wjandrea Jul 22 '21 at 05:07
  • @wjandrea Mutability is not relevant. An object has to be **hashable** to be added to a set. – Klaus D. Jul 22 '21 at 06:48
  • @Klaus Not relevant? Mutability implies non-hashability. I know technically they're separate things in Python, but if you write a mutable hashable class, you're asking for trouble. – wjandrea Jul 22 '21 at 06:56
  • ...for problems! And the job of a developer is solving problems. And BTW it is not that hard to do. – Klaus D. Jul 22 '21 at 06:58

2 Answers2

0

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'}]]
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • thank you so very much!! This is very helpful and has helped me move on with a project of mine! Just one follow up question: how may i access the 'type' key if it is in a nested dictionary. i.e., what if typeset = { nest1 [ {'id': 1, 'type': "a"}, {'id': 2, 'type': "a"}, {'id': 3, 'type': "b"}, {'id': 4, 'type': "b"}, {'id': 5, 'type': "a"} ] nest 2 [ {arbitrary dictionary here} ] } – Bharath Nagarajan Jul 23 '21 at 01:36
-1

You could use a list comprehension to pull out all the "type" values, then you can either push them through a set (or just leave it in the list) to compute the permutations.

from itertools import permutations

typeset = [...]  # what you named `set` in the question
types = [d["type"] for d in typeset]

# Optionally, push `types` through a `set` to get only the unique `type` values
# types = set(types)

combos = list(permutations(types, r=None))

In case you haven't looked, here's a link to the docs on permutations. r is entirely optional, but it would let you compute permutations of length r instead of len(types).


Alternatively, let's consider the case where you want the permutation of your List[Dict]:

from itertools import permutations

typeset = [...]  # as before
types = range(len(typeset))

combos = list(permutations(types, r=None))

You can now retrieve all permutations of typeset based on the indices stored in combos. However, depending on the size of your typeset, I wouldn't recommend it as that could consume quite a bit of memory.

John
  • 320
  • 2
  • 9