kezzos
kezzos

Reputation: 3221

Dictionary comprehension with nested list, prevent overwrite

I am trying to use a dictionary comprehension using a nested list. As long as the keys are unique, all works fine. However if there are multiples of the key present I would like to append the values to that key instead of overwriting the value. Is this possible using a comprehension?

seq1 = [[1, [1,2,3,4]], [2, [5,6,7]]]
seq2 = [[1, [1,2,3,4]], [1, [5,6,7]]]

print {key: [val] for key, val in seq1}  # Or dict(seq1)
>>> {1: [[1, 2, 3, 4]], 2: [[5, 6, 7]]}

print {key: [val] for key, val in seq2}
>>> {1: [[5, 6, 7]]}  # First value is overwritten

# Desired output:
def index_reads(reads):
    result = {}
    for i in reads:
        d = dict([i])
        for key, val in d.iteritems():
            if key in result:
                result[key].append(val)
            else:
                result[key] = [val]
    return result

print index_reads(seq1)
>>> {1: [[1, 2, 3, 4]], 2: [[5, 6, 7]]}

print index_reads(seq2)
>>> {1: [[1, 2, 3, 4], [5, 6, 7]]}

Sorry, I couldn't find a repeat of this question.

Upvotes: 1

Views: 480

Answers (3)

Richard Rublev
Richard Rublev

Reputation: 8162

Yes,with defaultdict works also:

from collections import defaultdict

seq1 = [[1, [1,2,3,4]], [2, [5,6,7]]]
seq2 = [[1, [1,2,3,4]], [1, [5,6,7]]]

d={key: [val] for key, val in seq1}
d = defaultdict(list)
for key, val in seq2:
    d[key].append(val)

print d

Then:

[(1, [[1, 2, 3, 4], [5, 6, 7]])

Or if we delete seq1,

seq2 = [[1, [1,2,3,4]], [1, [5,6,7]]]
d={key: [val] for key, val in seq2}
d = defaultdict(list)
for key, val in seq2:
    d[key].append(val)
print d

Again you will have:

defaultdict(<type 'list'>, {1: [[1, 2, 3, 4], [5, 6, 7]]})

Upvotes: 0

Paul Rooney
Paul Rooney

Reputation: 21619

You could use groupby from itertools.

import itertools
import operator

seq1 = [[1, [1,2,3,4]], [2, [5,6,7]]]
seq2 = [[1, [1,2,3,4]], [1, [5,6,7]]]

def index_reads(seq):
    return {k: [i[1] for i in g] for k, g in itertools.groupby(seq, operator.itemgetter(0))}

print index_reads(seq1)
print index_reads(seq2)

Output

{1: [[1, 2, 3, 4]], 2: [[5, 6, 7]]}   
{1: [[1, 2, 3, 4], [5, 6, 7]]}

Upvotes: 1

Kasravnd
Kasravnd

Reputation: 107347

You don't need list comprehension. As a more pythonic way you can use dict.setdefault() method :

>>> d={key: [val] for key, val in seq1}
>>> for key, val in seq2:
...   d.setdefault(key,[]).append(val)
... 
>>> d
{1: [[1, 2, 3, 4], [1, 2, 3, 4], [5, 6, 7]], 2: [[5, 6, 7]]}

You can also use collections.defaultdict for such tasks.

Also it shows its power when you have different keys in seq2 for example :

>>> seq2 = [[1, [1,2,3,4]], [5, [5,6,7]]]
>>> d={key: [val] for key, val in seq1}
>>> for key, val in seq2:
...   d.setdefault(key,[]).append(val)
... 
>>> d
{1: [[1, 2, 3, 4], [1, 2, 3, 4]], 2: [[5, 6, 7]], 5: [[5, 6, 7]]}

And if you don't want to keep duplicates you can use a defaultdict with set as container :

>>> from collections import defaultdict
>>> seq1 = [[1, [1,2,3,4]], [2, [5,6,7]]]
>>> seq2 = [[1, [1,2,3,4]], [1, [5,6,7]]]
>>> 
>>> d=defaultdict(set)
>>> for key, val in seq1+seq2:
...   d[key].add(tuple(val))
... 
>>> d
defaultdict(<type 'set'>, {1: set([(5, 6, 7), (1, 2, 3, 4)]), 2: set([(5, 6, 7)])})

Upvotes: 2

Related Questions