Edu C. Edu C. - 5 months ago 19
Python Question

Join lists with repeated values

First, this is what I have on the code so far, I'll give the explanation in a bit:

ll1 = [
'A',
'B',
'C',
'D'
]

l2 = [
['A', 10],
['B', 20],
['D', 5],
['A', 15],
['B', 30],
['C', 10],
['D', 15]
]

dc = dict(l2)
l3 = [[k, dc.get(k, 0)] for k in l1]


The result is this:

['A', 15]
['B', 30]
['C', 10]
['D', 15]


The first list l1 is made of a fixed number of keys and the second list l2 has the values to each key given in the first list. The l2 here is just one example as I'll be getting the values later (and these values are will be given as a list) but they'll have the same keys as l1. Every key needs to be shown, a key can be repeated, but some keys may have a null value (eg. the item C).

But when the list becomes the dict, the first value of each key is thrown away, returning unique keys for the dictionary.

How could it be done so that the result is similar to this one below?

['A', 10]
['B', 20]
['C', 0]
['D', 5]
['A', 15]
['B', 30]
['C', 10]
['D', 15]


Another example would be:

database_keys = [
'First Name',
'Last Name',
'Email',
'City'
]
database_input = [
['First Name', 'John'],
['Last Name', 'Doe'],
['Email', 'johndoe@test.com'],
['First Name', 'Jane'],
['Email', 'jane@test.com']
]

Output:
['First Name', 'John']
['Last Name', 'Doe']
['Email', 'johndoe@test.com']
['City', None]
['First Name', 'Jane']
['Last Name', None]
['Email', 'jane@test.com']
['City', None]

Answer

I would use a generator to fill in the missing values, just keep a cycle of the keys and when the next needed key is not the one in the data just produce the empty value:

import itertools
def fill_the_blanks(data, keys):
    keys = itertools.cycle(keys)
    for name, value in data:
        k = next(keys)
        while name!=k:
            yield [k,None]
            k = next(keys)
        yield [name,value]


>>> from pprint import pprint
>>> pprint( list(fill_the_blanks(l2, ll1)) )
[['A', 10],
 ['B', 20],
 ['C', None],
 ['D', 5],
 ['A', 15],
 ['B', 30],
 ['C', 10],
 ['D', 15]]
>>> pprint( list(fill_the_blanks(database_input,database_keys)) )
[['First Name', 'John'],
 ['Last Name', 'Doe'],
 ['Email', 'johndoe@test.com'],
 ['City', None],
 ['First Name', 'Jane'],
 ['Last Name', None],
 ['Email', 'jane@test.com']]

As an alternative, if you know that the first key 'First Name' will always mark the beginning of an entry why not just use dict.fromkeys then fill in until you reach the next 'first value':

def gen_dicts(data, keys):
    first_key = keys[0]
    entry = None #placeholder for first time
    for name, value in data:
        if name == first_key:
            if entry is not None: #skip first time
                yield entry
            entry = dict.fromkeys(keys)
        entry[name] = value
    yield entry #last one

>>> from pprint import pprint
>>> pprint( list(gen_dicts(l2, ll1)) )
[{'A': 10, 'B': 20, 'C': None, 'D': 5}, {'A': 15, 'B': 30, 'C': 10, 'D': 15}]
>>> pprint( list(gen_dicts(database_input, database_keys)) )
[{'City': None,
  'Email': 'johndoe@test.com',
  'First Name': 'John',
  'Last Name': 'Doe'},
 {'City': None,
  'Email': 'jane@test.com',
  'First Name': 'Jane',
  'Last Name': None}]
Comments