3

I'm trying to get a count of items in a list of lists and add those counts to a dictionary in Python. I have successfully made the list (it's a list of all possible combos of occurrences for individual ad viewing records) and a dictionary with keys equal to all the values that could possibly appear, and now I need to count how many times each occur and change the values in the dictionary to the count of their corresponding keys in the list of lists. Here's what I have:

import itertools
stuff=(1,2,3,4)
n=1
combs=list()
while n<=len(stuff):
    combs.append(list(itertools.combinations(stuff,n)))
    n = n+1
viewers=((1,3,4),(1,2,4),(1,4),(1,2),(1,4)) 
recs=list()
h=1
while h<=len(viewers):
    j=1
    while j<=len(viewers[h-1]):
       recs.append(list(itertools.combinations(viewers[h-1],j))) 
       j=j+1
    h=h+1
showcount={}
for list in combs:
    for item in list:
        showcount[item]=0    
for k, v in showcount:
        for item in recs:
            for item in item:
                if item == k:
                    v = v+1

I've tried a bunch of different ways to do this, and I usually either get 'too many values to unpack' errors or it simply doesn't populate. There are several similar questions posted but I'm pretty new to Python and none of them really addressed what I needed close enough for me to figure it out. Many thanks.

TomR
  • 546
  • 8
  • 19

4 Answers4

10

Use a Counter instead of an ordinary dict to count things:

from collections import Counter

showcount = Counter()
for item in recs:
    showcount.update(item)

or even:

from collections import Counter
from itertools import chain

showcount = Counter(chain.from_iterable(recs))

As you can see that makes your code vastly simpler.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
0

First, 'flatten' the list using a generator expression: (item for sublist in combs for item in sublist).

Then, iterate over the flattened list. For each item, you either add an entry to the dict (if it doesn't already exist), or add one to the value.

d = {}
for key in (item for sublist in combs for item in sublist):
    try:
        d[key] += 1
    except KeyError:  # I'm not certain that KeyError is the right one, you might get TypeError. You should check this
        d[key] = 1

This technique assumes all the elements of the sublists are hashable and can be used as keys.

Benjamin Hodgson
  • 42,952
  • 15
  • 108
  • 157
  • 1
    A `defaultdict` would already be vastly simpler (`d = defaultdict(int)`) as it removes the need for the `try`/`except`; but a `Counter` makes it simpler still as you don't even have to do the counting yourself. – Martijn Pieters Oct 15 '12 at 17:09
  • @MartijnPieters You're right, and your answer is the better one. I just wanted to show that it could be done using only the builtins. – Benjamin Hodgson Oct 15 '12 at 17:11
  • 2
    Don't ignore the standard library though! It's things like `Counter` and `defaultdict` that make Python shine so bright! – Martijn Pieters Oct 15 '12 at 17:16
  • it's possible to stay w/ the builtins and still avoid the `try/except`: `d[key] = d.get(key,0) + 1` – reedstrm Oct 15 '12 at 17:20
  • @reedstrm: yes, or by testing the `key in d` construct. However this is often slower than the `try` statement. – Benjamin Hodgson Oct 15 '12 at 17:22
0

If all you want to do is flatten your list of lists you can use itertools.chain()

>>> import itertools
>>> listOfLists = ((1,3,4),(1,2,4),(1,4),(1,2),(1,4)) 
>>> flatList = itertools.chain.from_iterable(listOfLists)

The Counter object from the collections module will probably do the rest of what you want.

>>> from collections import Counter
>>> Counter(flatList)
Counter({1: 5, 4: 4, 2: 2, 3: 1})
Matt
  • 3,651
  • 3
  • 16
  • 35
  • 1
    `itertools.chain(*listOfLists)` is more efficiently/Pythonically written as `itertools.chain.from_iterable(listOfLists)` – Jon Clements Oct 15 '12 at 17:43
0

I have some old code that resembles the issue, it might prove useful to people facing a similar problem.

import sys
file = open(sys.argv[-1], "r").read()
wordictionary={}
for word in file.split():
    if word not in wordictionary:
        wordictionary[word] = 1
    else:
        wordictionary[word] += 1
sortable = [(wordictionary[key], key) for key in wordictionary]
sortable.sort()
sortable.reverse()
for member in sortable: print (member)
Java Riser
  • 320
  • 3
  • 9