Reputation: 4581
I want to generate combinations of an object of lists in Python and was looking into itertools.product
or similar functions to calculate combinations. Since itertools
.product generates combinations from multiple arrays
I have an object that looks like this:
{
"Cities": [
{
"Id": 1,
"Value": "New York"
},
{
"Id": 2,
"Value": "Boston"
}
],
"People": [
{
"Id": 1,
"Value": "Michael"
},
{
"Id": 2,
"Value": "Ryan"
},
{
"Id": 3,
"Value": "Jim"
},
{
"Id": 4,
"Value": "Phyllis"
}
]
}
And I want to generate a list that shows all combinations of people living in each city. So in the case above a list of 8 values.
My code below looks like:
import json
import itertools
def main():
combinations = []
with open('people.json') as f:
data = json.load(f)
combinations = list(itertools.product(*data))
print(combinations)
if __name__ == "__main__":
main()
When running I get a completely different result:
How can I modify my code to get the result I want?
Note: It doesn't have to use itertools
, I just thought itertools
is used for calculations like these
Upvotes: 1
Views: 611
Reputation: 25490
When you do list(itertools.product(*data))
, the same thing is passed to product
that you see when you do:
for x in data:
print(x)
ie., you did
itertools.product(['Cities', 'People'])
which is why you got the product of the characters in those two strings (yay duck typing!)
[
('C', 'P'),
('C', 'e'),
('C', 'o'),
('C', 'p'),
('C', 'l'),
('C', 'e'),
('i', 'P'),
('i', 'e'),
('i', 'o'),
('i', 'p'),
('i', 'l'),
('i', 'e'),
...
]
You're using product()
right, but giving it the wrong data.
cities = [c['Value'] for c in data['Cities']] # Extract all cities Value from list-of-dicts
people = [c['Value'] for c in data['People']] # Extract all people Value from list-of-dicts
print(list(itertools.product(cities, people))) # Product
This gives the output:
[
('New York', 'Michael'),
('New York', 'Ryan'),
('New York', 'Jim'),
('New York', 'Phyllis'),
('Boston', 'Michael'),
('Boston', 'Ryan'),
('Boston', 'Jim'),
('Boston', 'Phyllis')
]
If you want the dict
objects instead of the Value
keys, you can simply pass those objects to product()
:
print(list(itertools.product(data['Cities'], data['People']))) # Product
which gives
[
({'Id': 1, 'Value': 'New York'}, {'Id': 1, 'Value': 'Michael'}),
({'Id': 1, 'Value': 'New York'}, {'Id': 2, 'Value': 'Ryan'}),
({'Id': 1, 'Value': 'New York'}, {'Id': 3, 'Value': 'Jim'}),
({'Id': 1, 'Value': 'New York'}, {'Id': 4, 'Value': 'Phyllis'}),
({'Id': 2, 'Value': 'Boston'}, {'Id': 1, 'Value': 'Michael'}),
({'Id': 2, 'Value': 'Boston'}, {'Id': 2, 'Value': 'Ryan'}),
({'Id': 2, 'Value': 'Boston'}, {'Id': 3, 'Value': 'Jim'}),
({'Id': 2, 'Value': 'Boston'}, {'Id': 4, 'Value': 'Phyllis'})
]
as expected.
Upvotes: 2
Reputation: 8625
To perform the job you have described, using the data you have shown, this script will do it:
import json
import itertools
def main():
combinations = []
with open('people.json') as f:
data = json.load(f)
combinations = list(itertools.product(data['Cities'], data['People']))
print(combinations)
if __name__ == "__main__":
main()
The only difference is that I'm specifying which data to use from the data structure.
The output (I have formatted it for readability):
[
({"Id": 1, "Value": "New York"},
{"Id": 1, "Value": "Michael"}),
({"Id": 1, "Value": "New York"},
{"Id": 2, "Value": "Ryan"}),
({"Id": 1, "Value": "New York"},
{"Id": 3, "Value": "Jim"}),
({"Id": 1, "Value": "New York"},
{"Id": 4, "Value": "Phyllis"}),
({"Id": 2, "Value": "Boston"},
{"Id": 1, "Value": "Michael"}),
({"Id": 2, "Value": "Boston"},
{"Id": 2, "Value": "Ryan"}),
({"Id": 2, "Value": "Boston"},
{"Id": 3, "Value": "Jim"}),
({"Id": 2, "Value": "Boston"},
{"Id": 4, "Value": "Phyllis"})
]
If you instead wanted to perform a product
between whatever keys are in the data set, you would want to do itertools.product(data.values())
, but the code I have shown is clearer.
Upvotes: 2