Search code examples
pythonpython-3.xpython-assignment-expression

Walrus to unpack values within a list comprehension


I have a nested list holding dictionaries as mapping table using a tuple as key. I am struggling to zip the dictionary together so it can be exported by Pandas to csv file:

l = [{('A', 'B'): 1}, {('A', 'C'): 2}, {('A', 'D'): 3}]


def dynDictCombiner(item):
    # would lambda be faster?
    def _combine(item):
        key = item.keys()[0]
        return key, item[key]

    col_keys = ('start', 'stop')
    row_keys = ('value')

    # syntax error
    l = [dict(zip(col_keys + row_keys, k + v)) for ((k, v) :=_combine(item) in l)]
    print(l)


l = dynDictCombiner(l)
#import pandas as pd
#df = pd.DataFrame.from_dict(l)
#print(df.shape)
#print(df)
#df.to_csv(path_or_buf='C:/temp/foo.csv', index=False, header=True)

Expected Output:

[
{'start': 'A', 'stop': 'B', 'value': 1},
{'start': 'A', 'stop': 'C', 'value': 2},
{'start': 'A', 'stop': 'D', 'value': 3}
]

Edit, function without walrus:

def dynDictCombinerSimple(items):
    # would lambda be faster?
    def _combine(item):
        key = list(item.keys())[0]
        return key, (item[key], )

    col_keys = ('start', 'stop')
    row_keys = ('value', )

    result = []
    for item in items:
        k, v = _combine(item)
        result.append(dict(zip(col_keys + row_keys, k + v)))
    print(result)

Out as expected:

[{'start': 'A', 'stop': 'B', 'value': 1}, {'start': 'A', 'stop': 'C', 'value': 2}, {'start': 'A', 'stop': 'D', 'value': 3}]

Solution

  • @MafMal: Please add all relevant information to the question upfront, so it's easier to understand, right now the most relevant information are in the comments.

    I interpret an answer to your question like this:

    l2 = [
        # rows are dicts as mentioned in the comments
        {
            ('A', 'B', 'C'): {
                'foo': 'bar1'
            }
        }, {
            ('A', 'C', 'D'): {
                'foo': 'bar2'
            }
        }, {
            ('A', 'D', 'E'): {
                'foo': 'bar3'
            }
        }
    ]
    
    def genericDictCombiner(items, col_keys=('start', 'stop')):
        result = []
        for item in items:
            # As there is just one key/value pair, 
            # possibly that's why you came up with that _combine thing!
            for k, v in item.items():
                resDct = dict(zip(col_keys, k))
                resDct.update(v)
                result.append(resDct)
        return result
     
    
    l = genericDictCombiner(l2)
    print(l)
    

    Out:

    [{'start': 'A', 'stop': 'B', 'foo': 'bar1'}, {'start': 'A', 'stop': 'C', 'foo': 'bar2'}, {'start': 'A', 'stop': 'D', 'foo': 'bar3'}]