Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to count size of lists with a dict?

If I have a dict of lists like:

{
    'id1': ['a', 'b', 'c'],
    'id2': ['a', 'b'],
    # etc.
}

and I want to tally the size of the lists, i.e.. the number of ids >0, >1, >2...etc

Is there an easier way than nested for loops like this:

dictOfOutputs = {}
for x in range(1,11):
    count = 0
    for agentId in userIdDict:
        if len(userIdDict[agentId]) > x:
            count += 1
    dictOfOutputs[x] = count        
return dictOfOutputs
like image 823
DBWeinstein Avatar asked May 11 '15 16:05

DBWeinstein


1 Answers

I'd use a collections.Counter() object to collect lengths, then accumulate the sums:

from collections import Counter

lengths = Counter(len(v) for v in userIdDict.values())
total = 0
accumulated = {}
for length in range(max(lengths), -1, -1):
    count = lengths.get(length, 0)
    total += count
    accumulated[length] = total

So this collects counts for each length, then builds a dictionary with accumulative lengths. This is a O(N) algorithm; you loop over all values once, then add on some smaller straight loops (for max() and the accumulation loop):

>>> from collections import Counter
>>> import random
>>> testdata = {''.join(random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(5)): [None] * random.randint(1, 10) for _ in range(100)}
>>> lengths = Counter(len(v) for v in testdata.values())
>>> lengths
Counter({8: 14, 7: 13, 2: 11, 3: 10, 4: 9, 5: 9, 9: 9, 10: 9, 1: 8, 6: 8})
>>> total = 0
>>> accumulated = {}
>>> for length in range(max(lengths), -1, -1):
...     count = lengths.get(length, 0)
...     total += count
...     accumulated[length] = total
... 
>>> accumulated
{0: 100, 1: 100, 2: 92, 3: 81, 4: 71, 5: 62, 6: 53, 7: 45, 8: 32, 9: 18, 10: 9}
like image 87
Martijn Pieters Avatar answered Oct 26 '22 22:10

Martijn Pieters