Helmi
Helmi

Reputation: 539

Build pairs from dictionary

My data is a nested dicitionary of people in countries. Here's what it looks like with unimportant stuff removed:

{'DE': [{'createdTime': '2017-11-03T13:41:01.000Z',
         'fields': {'Land': 'DE', 'Teilnehmer': 'James Hunt'},
         'id': 'reccgdSZXZFvAztCT'},
        {'createdTime': '2017-11-04T12:50:21.000Z',
         'fields': {'Land': 'DE', 'Teilnehmer': 'Susie Mueller'},
         'id': 'recQhmPmTrlZzoI84'},
        {'createdTime': '2017-11-04T12:50:33.000Z',
         'fields': {'Land': 'DE', 'Teilnehmer': 'Tom Tikky'},
         'id': 'recKCh99xvQwwCmSp'}],
 'UK': [{'createdTime': '2017-11-03T13:41:01.000Z',
         'fields': {'Land': 'UK', 'Teilnehmer': 'John Doe'},
         'id': 'recFTlSMXNET6e2UX'},
        {'createdTime': '2017-11-03T14:16:00.000Z',
         'fields': {'Land': 'UK', 'Teilnehmer': 'Jane Smith'},
         'id': 'recLqDHWh14TLm30g'},
        {'createdTime': '2017-11-03T18:41:56.000Z',
         'fields': {'Land': 'UK', 'Teilnehmer': 'Claire Singer'},
         'id': 'recB8XaFb7va0lT50'}]}

It has previously been sorted by country already. I now need to build sender/receiver pairs and everyone needs to be in two pairs - once as the sender, once as the receiver. Both sides need to be from the same country. So with the sample data from above there will be 3 pairs per country at the end.

All that matters on the output is the id. Basically I thought a list would work at the output but I'm not sure if those are reliable when it comes to the order of elements within the list. Apart from that this is what the result could look like:

[
    # DE Pairs
    ['reccgdSZXZFvAztCT', 'recQhmPmTrlZzoI84'],
    ['recQhmPmTrlZzoI84', 'recKCh99xvQwwCmSp'],
    ['recKCh99xvQwwCmSp', 'reccgdSZXZFvAztCT'],
    # UK Pairs
    ['recFTlSMXNET6e2UX', 'recLqDHWh14TLm30g'],
    ['recLqDHWh14TLm30g', 'recB8XaFb7va0lT50'],
    ['recB8XaFb7va0lT50', 'recFTlSMXNET6e2UX']
]

Everything that came to my mind to solve this involves several levels of for loops but I still didn't manage to get it done. I'm very sure there must be a pythonic way to solve this. Any ideas?

Upvotes: 1

Views: 60

Answers (2)

Patrick Haugh
Patrick Haugh

Reputation: 60974

from itertools import combinations

d = {
    'DE': [{'createdTime': '2017-11-03T13:41:01.000Z',
     'fields': {'Land': 'DE', 'Teilnehmer': 'James Hunt'},
     'id': 'reccgdSZXZFvAztCT'},
    {'createdTime': '2017-11-04T12:50:21.000Z',
     'fields': {'Land': 'DE', 'Teilnehmer': 'Susie Mueller'},
     'id': 'recQhmPmTrlZzoI84'},
    {'createdTime': '2017-11-04T12:50:33.000Z',
     'fields': {'Land': 'DE', 'Teilnehmer': 'Tom Tikky'},
     'id': 'recKCh99xvQwwCmSp'}],
    'UK': [{'createdTime': '2017-11-03T13:41:01.000Z',
     'fields': {'Land': 'UK', 'Teilnehmer': 'John Doe'},
     'id': 'recFTlSMXNET6e2UX'},
    {'createdTime': '2017-11-03T14:16:00.000Z',
     'fields': {'Land': 'UK', 'Teilnehmer': 'Jane Smith'},
     'id': 'recLqDHWh14TLm30g'},
    {'createdTime': '2017-11-03T18:41:56.000Z',
     'fields': {'Land': 'UK', 'Teilnehmer': 'Claire Singer'},
     'id': 'recB8XaFb7va0lT50'}]}
l = [list(combinations((x['id'] for x in v), 2)) for v in d.values()]

gives us

[[('recFTlSMXNET6e2UX', 'recLqDHWh14TLm30g'),
  ('recFTlSMXNET6e2UX', 'recB8XaFb7va0lT50'),
  ('recLqDHWh14TLm30g', 'recB8XaFb7va0lT50')],
 [('reccgdSZXZFvAztCT', 'recQhmPmTrlZzoI84'),
  ('reccgdSZXZFvAztCT', 'recKCh99xvQwwCmSp'),
  ('recQhmPmTrlZzoI84', 'recKCh99xvQwwCmSp')]]

Edit:

results = []
for country in d.values():
    ids = [people['id'] for people in country]
    rotated_ids = ids[1:] + ids[:1]
    for a, b in zip(ids, rotated_ids):
        results.append([a, b])

Would give us something more like

[['recFTlSMXNET6e2UX', 'recLqDHWh14TLm30g'],
 ['recLqDHWh14TLm30g', 'recB8XaFb7va0lT50'],
 ['recB8XaFb7va0lT50', 'recFTlSMXNET6e2UX'],
 ['reccgdSZXZFvAztCT', 'recQhmPmTrlZzoI84'],
 ['recQhmPmTrlZzoI84', 'recKCh99xvQwwCmSp'],
 ['recKCh99xvQwwCmSp', 'reccgdSZXZFvAztCT']]

Upvotes: 1

Blckknght
Blckknght

Reputation: 104712

There's not just one way to produce the pairs you want, at least, not if the number of people in a country is greater than 2. So you'll need to pick a way to select pairs so that each person is on each end exactly once.

One simple approach is to have each person send to the person after them in the country list. Wrap around so that the last person sends to the first, and you have a working algorithm.

Here's a list comprehension that I think does what you want:

result = [(p[i-1]['id'], p[i]['id']) for p in data.values() for i in range(len(p))]

In the comprehension, p is a list of dictionaries representing people from a single country and i is an index into p. We allow i-1 to be -1 at the start, as that handles the "wrap around" case we need to make the pairs work the way you want.

Upvotes: 1

Related Questions