Nathalie Gómez
Nathalie Gómez

Reputation: 13

Add values of repeated items from list to a dictionary

I have the list

list1 = [['P', '2.1'], ['C', '4.1'], ['S', '4.2'], ['M', '5.3'], ['A', '4.1'], ['C', '3.8'], ['C', '3.9'], ['M', '5.2'], ['A', '4.3'], ['P', '2.3'], ['C', '4.2'], ['A', '4.4']]

and i have to create a dictionary adding the values of repeated items.

so far I have this:

for line in carsList:
     model = line[0]
     carsDict.update({model:[]})
     if model in carsDict:
         carsDict[model].append(float(line[1]))

But when I print what i got is: {'P': [2.3], 'C': [4.2], 'S': [4.2], 'M': [5.2], 'A': [4.4]}

Thanks.

Upvotes: 1

Views: 96

Answers (5)

RoadRunner
RoadRunner

Reputation: 26315

You can use a collections.defaultdict to group by the first item of each sublist:

from collections import defaultdict

list1 = [['P', '2.1'], ['C', '4.1'], ['S', '4.2'], ['M', '5.3'], ['A', '4.1'], ['C', '3.8'], ['C', '3.9'], ['M', '5.2'], ['A', '4.3'], ['P', '2.3'], ['C', '4.2'], ['A', '4.4']]

d = defaultdict(list)
for x, y in list1:
    d[x].append(float(y))

print(dict(d))
# {'P': [2.1, 2.3], 'C': [4.1, 3.8, 3.9, 4.2], 'S': [4.2], 'M': [5.3, 5.2], 'A': [4.1, 4.3, 4.4]}

print({k: sum(map(float, v)) for k, v in d.items()})
# {'P': 4.4, 'C': 16.0, 'S': 4.2, 'M': 10.5, 'A': 12.799999999999999}

If we are only interested in summing the floats, using a defaultdict(float) is probably more faster than collecting all the floats in a list then applying sum():

d = defaultdict(float)
for x, y in list1:
    d[x] += float(y)

print(dict(d))
# {'P': 4.4, 'C': 16.0, 'S': 4.2, 'M': 10.5, 'A': 12.799999999999999}

Also note that defaultdict is a subclass of dict, so the dict() cast is not needed.

You could also sort by the first item then apply itertools.groupby:

from itertools import groupby

list1 = [['P', '2.1'], ['C', '4.1'], ['S', '4.2'], ['M', '5.3'], ['A', '4.1'], ['C', '3.8'], ['C', '3.9'], ['M', '5.2'], ['A', '4.3'], ['P', '2.3'], ['C', '4.2'], ['A', '4.4']]

print({k: [float(x[1]) for x in g] for k, g in groupby(sorted(list1), key=lambda x: x[0])})
# {'A': [4.1, 4.3, 4.4], 'C': [3.8, 3.9, 4.1, 4.2], 'M': [5.2, 5.3], 'P': [2.1, 2.3], 'S': [4.2]}

print({k: sum(float(x[1]) for x in g) for k, g in groupby(sorted(list1), key=lambda x: x[0])})
# {'A': 12.799999999999999, 'C': 16.0, 'M': 10.5, 'P': 4.4, 'S': 4.2}

Both solutions above show how to group and get the sum of the floats. The groupby solution is slower for grouping because it is using O(NLogN) sorting, whereas the defaultdict groups in O(N) time. We could also replace key=lambda x: x[0] with operator.itemgetter(0), which is slightly faster. More information about the speed difference between the two in this answer.

Upvotes: 1

Nick
Nick

Reputation: 147156

I've interpreted your question as meaning you want to sum the values for each key. There's a couple of ways you can achieve this. Using a defaultdict is probably the simplest:

from collections import defaultdict

carsDict = defaultdict(float)

for l in list1:
    carsDict[l[0]] += float(l[1])

print({ k : v for k, v in carsDict.items() })

but you can also implement it as a dictionary comprehension:

carsDict = { k : sum(float(l[1]) for l in list1 if l[0] == k) for k in set(l[0] for l in list1) }
print(carsDict)

In both cases the output is

{'C': 16.0, 'M': 10.5, 'S': 4.2, 'P': 4.4, 'A': 12.799999999999999}

Upvotes: 1

Nemo Zhang
Nemo Zhang

Reputation: 146

You cleared the list every time by updating it to an empty list, so you only gets the last element.

for line in carsList:
     model = line[0]
     carsDict.update({model:[]}) # It clears out your list every time!
     if model in carsDict:
         carsDict[model].append(float(line[1]))

This is what you should do. You create a new list when it does not exist, and append to it if there is already a list.

for line in carsList:
    model = line[0]
    if not model in carsDict:
        carsDict[model]=[]
    carsDict[model].append(float(line[1]))
# {'A': [4.1, 4.3, 4.4], 'P': [2.1, 2.3], 'C': [4.1, 3.8, 3.9, 4.2], 'M': [5.3, 5.2], 'S': [4.2]}

If you want to calculate a sum of all the floats:

for line in carsList:
    model = line[0]
    if not model in carsDict:
        carsDict[model]=0
    carsDict[model]+=float(line[1])
# {'A': 12.8, 'P': 4.4, 'C': 16.0, 'M': 10.5, 'S': 4.2}

Upvotes: 1

Thibauld Croonenborghs
Thibauld Croonenborghs

Reputation: 141

Every time you run through the for loop, you reset the value of model to an empty list in your carsDict.

what you can do is:

for line in carsList:
    model = line[0]
    if model in carsDict:
        carsDict[model].append(float(line[1]))
    else:
        carsDict[model] = [float(line[1])]

Upvotes: 1

Rakesh
Rakesh

Reputation: 82765

Use dict.setdefault

Ex:

list1 = [['P', '2.1'], ['C', '4.1'], ['S', '4.2'], ['M', '5.3'], ['A', '4.1'], ['C', '3.8'], ['C', '3.9'], ['M', '5.2'], ['A', '4.3'], ['P', '2.3'], ['C', '4.2'], ['A', '4.4']]
result = {}

for k, v in list1:
    result.setdefault(k, []).append(v)

print(result)

or collections.defaultdict

from collections import defaultdict
result = defaultdict(list)

Output:

{'A': ['4.1', '4.3', '4.4'],
 'C': ['4.1', '3.8', '3.9', '4.2'],
 'M': ['5.3', '5.2'],
 'P': ['2.1', '2.3'],
 'S': ['4.2']}

Upvotes: 1

Related Questions