0

I am having the following difficulty: Given my input dictionary with 4 keys and their values e.g.

global_dict = {'Cloudy': (False, True),
               'Rain': False,
               'Sprinkler': (False, True),
               'WetGrass': (False, True)}

I want to get all possible sub dictionaries with only one value for each key; preferably in a list e.g.

dict_list = [
    {'WetGrass': False, 'Rain': False, 'Sprinkler': False, 'Cloudy': False},
    {'WetGrass': False, 'Rain': False, 'Sprinkler': False, 'Cloudy': True},
    {'WetGrass': False, 'Rain': False, 'Sprinkler': True, 'Cloudy': False},
    {'WetGrass': False, 'Rain': False, 'Sprinkler': True, 'Cloudy': True},
    {'WetGrass': True, 'Rain': False, 'Sprinkler': False, 'Cloudy': False},
    {'WetGrass': True, 'Rain': False, 'Sprinkler': False, 'Cloudy': True},
    {'WetGrass': True, 'Rain': False, 'Sprinkler': True, 'Cloudy': False},
    {'WetGrass': True, 'Rain': False, 'Sprinkler': True, 'Cloudy': True}
]

I tried already the following:

src = {'lblA': (False, True), 'lblB': (False, True), 'lblC': (0, 1, 2)}
labels, terms = zip(*src.items())
print [dict(zip(labels, term)) for term in itertools.product(*terms)]

From here:

Best way to enumerate a cartesian product with labels in python?

But I keep getting the error:

TypeError 'bool' object is not iterable

I hope someone can help me out.

Thank you!

Azat Ibrakov
  • 9,998
  • 9
  • 38
  • 50
SolingerMUC
  • 33
  • 1
  • 8

1 Answers1

2

Initial problem here is that all of your values are tuples except 'Rain' (which value is bool and it is not iterable), so i've made it tuple as well:

global_dict = {'Cloudy': (False, True),
               'Rain': (False,),
               'Sprinkler': (False, True),
               'WetGrass': (False, True)}

where (False,) is single-element tuple.

Finally we can create dict_list using itertools.product like

from itertools import product

global_dict = {'Cloudy': (False, True),
               'Rain': (False,),
               'Sprinkler': (False, True),
               'WetGrass': (False, True)}

possible_values = product(*global_dict.values())
dict_list = [dict(zip(global_dict.keys(), values))
             for values in possible_values]

gives us

>>>dict_list
[{'Cloudy': False, 'Rain': False, 'Sprinkler': False, 'WetGrass': False},
 {'Cloudy': False, 'Rain': False, 'Sprinkler': False, 'WetGrass': True},
 {'Cloudy': False, 'Rain': False, 'Sprinkler': True, 'WetGrass': False},
 {'Cloudy': False, 'Rain': False, 'Sprinkler': True, 'WetGrass': True},
 {'Cloudy': True, 'Rain': False, 'Sprinkler': False, 'WetGrass': False},
 {'Cloudy': True, 'Rain': False, 'Sprinkler': False, 'WetGrass': True},
 {'Cloudy': True, 'Rain': False, 'Sprinkler': True, 'WetGrass': False},
 {'Cloudy': True, 'Rain': False, 'Sprinkler': True, 'WetGrass': True}]

Test

desired_dict_list = [
    {'WetGrass': False, 'Rain': False, 'Sprinkler': False, 'Cloudy': False},
    {'WetGrass': False, 'Rain': False, 'Sprinkler': False, 'Cloudy': True},
    {'WetGrass': False, 'Rain': False, 'Sprinkler': True, 'Cloudy': False},
    {'WetGrass': False, 'Rain': False, 'Sprinkler': True, 'Cloudy': True},
    {'WetGrass': True, 'Rain': False, 'Sprinkler': False, 'Cloudy': False},
    {'WetGrass': True, 'Rain': False, 'Sprinkler': False, 'Cloudy': True},
    {'WetGrass': True, 'Rain': False, 'Sprinkler': True, 'Cloudy': False},
    {'WetGrass': True, 'Rain': False, 'Sprinkler': True, 'Cloudy': True}
]

assert (len(dict_list) == len(desired_dict_list) and
        all(dictionary in dict_list
            for dictionary in desired_dict_list))
Azat Ibrakov
  • 9,998
  • 9
  • 38
  • 50
  • Hey Azat thank you very much! That was exactly what I wanted to achieve! Can you explain me why I got the error above? And what does the * in front of global_dict.values() do? What is its effect? – SolingerMUC Jun 26 '17 at 11:01
  • @SolingerMUC: ok, give me a minute – Azat Ibrakov Jun 26 '17 at 11:03
  • I do not see where and how you changed the boolean value into a tuple :O – SolingerMUC Jun 26 '17 at 11:28
  • @SolingerMUC: `(value,)` is a single-element tuple, but remember that `(value)` will not create tuple, so comma is significant – Azat Ibrakov Jun 26 '17 at 11:32
  • But how do you change it if in the given global_dict the value ist only a boolean variable ? – SolingerMUC Jun 26 '17 at 11:36
  • @SolingerMUC: is it your case? – Azat Ibrakov Jun 26 '17 at 11:39
  • Yes in my code I get the global dict and some of the values are single boolean variables so I cannot just change them "manually" to single-element tuples :S – SolingerMUC Jun 26 '17 at 11:42
  • @SolingerMUC: all other objects are tuples? – Azat Ibrakov Jun 26 '17 at 11:45
  • Not always, it is possible, that some other keys also have boolean values instead of tuples. It is even possible, that all values are boolean. In that case this list should only contain one element, because there are no other combinations possible. – SolingerMUC Jun 26 '17 at 11:48
  • @SolingerMUC: there are only `tuple`s and `bool`s in this `dict`? – Azat Ibrakov Jun 26 '17 at 11:55
  • Yes and if there are tuples, they are always the tuple (False,True) – SolingerMUC Jun 26 '17 at 11:57
  • Hey Azat, I think your solution on tuples is sufficient for me! In effect it does not make sense that there are different types (e.g. bool and tuple). I just changed all boolean variables into a single-element tuples! Thanks a lot for your help! – SolingerMUC Jun 26 '17 at 13:28