Jebathon
Jebathon

Reputation: 4581

Using itertools library to get combinations of objects?

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:

enter image description here

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

Answers (2)

pho
pho

Reputation: 25490

Why you get the output that you do:

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'),
 ...
]

How to get the output you want:

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

lxop
lxop

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

Related Questions