32

I want to get the number of times x appears in the nested list.

if the list is:

list = [1, 2, 1, 1, 4]
list.count(1)
>>3

This is OK. But if the list is:

list = [[1, 2, 3],[1, 1, 1]]

How can I get the number of times 1 appears? In this case, 4.

Shane Kao
  • 185
  • 1
  • 11
Yugo Kamo
  • 2,349
  • 4
  • 18
  • 13

8 Answers8

61
>>> L = [[1, 2, 3], [1, 1, 1]]
>>> sum(x.count(1) for x in L)
4
Thomas Edleson
  • 2,175
  • 1
  • 16
  • 19
15

itertools and collections modules got just the stuff you need (flatten the nested lists with itertools.chain and count with collections.Counter

import itertools, collections

data = [[1,2,3],[1,1,1]]
counter = collections.Counter(itertools.chain(*data))
print counter[1]

Use a recursive flatten function instead of itertools.chain to flatten nested lists of arbitrarily level depth

import operator, collections

def flatten(lst):
    return reduce(operator.iadd, (flatten(i) if isinstance(i, collections.Sequence) else [i] for i in lst))

reduce with operator.iadd has been used instead of sum so that the flattened is built only once and updated in-place

Imran
  • 87,203
  • 23
  • 98
  • 131
15

Here is yet another approach to flatten a nested sequence. Once the sequence is flattened it is an easy check to find count of items.

def flatten(seq, container=None):
    if container is None:
        container = []

    for s in seq:
        try:
            iter(s)  # check if it's iterable
        except TypeError:
            container.append(s)
        else:
            flatten(s, container)

    return container


c = flatten([(1,2),(3,4),(5,[6,7,['a','b']]),['c','d',('e',['f','g','h'])]])
print(c)
print(c.count('g'))

d = flatten([[[1,(1,),((1,(1,))), [1,[1,[1,[1]]]], 1, [1, [1, (1,)]]]]])
print(d)
print(d.count(1))

The above code prints:

[1, 2, 3, 4, 5, 6, 7, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
1
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
12
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
sateesh
  • 27,947
  • 7
  • 36
  • 45
  • 2
    This example crashes my kernel. – Peter.k Feb 10 '19 at 12:53
  • This results in stack overflow because a string like `'a'` is actually iterable. That means it will just keep calling recursion on it. – paxdiablo Oct 16 '20 at 02:11
  • hmm I am bit embarrassed, it is quite long ago (9 yrs) that I posted this code, and usually I run and test my code before posting. Now when I check both with python/2.7 and python/3.7 the above code crashes. So not sure if the above code was crashing even with the python interpreter that I ran the above code (I don't recall what version it was) and if behavior of `iter` changed between the versions or the code I posted was wrong from the day I posted and the error remained undetected. – sateesh Oct 17 '20 at 16:28
9

Try this:

reduce(lambda x,y: x+y,list,[]).count(1)

Basically, you start with an empty list [] and add each element of the list list to it. In this case the elements are lists themselves and you get a flattened list.

PS: Just got downvoted for a similar answer in another question!

PPS: Just got downvoted for this solution as well!

manojlds
  • 290,304
  • 63
  • 469
  • 417
  • 5
    People are arbitrarily downvoting here. Downvote for crappy solutions. Mine definitely is not. And there is no mention of arbitrary nesting mentioned and works for the OP's case. Don't over think. – manojlds Apr 29 '11 at 05:34
  • Yes, because you are refusing to think a step further and provide some more insight into the deeper problem and how to find a more general solution. –  Apr 29 '11 at 05:46
  • 5
    .. so says the person who says search on Google. – user225312 Apr 29 '11 at 05:46
  • Great answer. Who cares about what @AndreasJung says. The answer fits the question. – Jimmy Kane Feb 07 '14 at 13:09
4

If there is only one level of nesting flattening can be done with this list comprenension:

>>> L = [[1,2,3],[1,1,1]]
>>> [ item for sublist in L for item in sublist ].count(1)
4
>>> 
dting
  • 38,604
  • 10
  • 95
  • 114
4

For the heck of it: count to any arbitrary nesting depth, handling tuples, lists and arguments:

hits = lambda num, *n: ((1 if e == num else 0)
    for a in n
        for e in (hits(num, *a) if isinstance(a, (tuple, list)) else (a,)))

lst = [[[1,(1,),((1,(1,))), [1,[1,[1,[1]]]], 1, [1, [1, (1,)]]]]]
print sum(hits(1, lst, 1, 1, 1))

15
samplebias
  • 37,113
  • 6
  • 107
  • 103
  • 1
    +1 for the coolest ``lambda`` abuser around here ;-). This also answers the question how to recursively embed a generator in itself :-). – ThomasH Apr 29 '11 at 08:41
1
def nested_count(lst, x):
    return lst.count(x) + sum(
        nested_count(l,x) for l in lst if isinstance(l,list))

This function returns the number of occurrences, plus the recursive nested count in all contained sub-lists.

>>> data = [[1,2,3],[1,1,[1,1]]]
>>> print nested_count(data, 1)
5
shang
  • 24,642
  • 3
  • 58
  • 86
0

The following function will flatten lists of lists of any depth(a) by adding non-lists to the resultant output list, and recursively processing lists:

def flatten(listOrItem, result = None):
    if result is None: result = []      # Ensure initial result empty.

    if type(listOrItem) != type([]):    # Handle non-list by appending.
        result.append(listOrItem)
    else:
        for item in listOrItem:         # Recursively handle each item in a list.
            flatten(item, result)
    return result                       # Return flattened container.

mylist = flatten([[1,2],[3,'a'],[5,[6,7,[8,9]]],[10,'a',[11,[12,13,14]]]])
print(f'Flat list is {mylist}, count of "a" is {mylist.count("a")}')

print(flatten(7))

Once you have a flattened list, it's a simple matter to use count on it. The output of that code is:

Flat list is [1, 2, 3, 'a', 5, 6, 7, 8, 9, 10, 'a', 11, 12, 13, 14], count of "a" is 2
[7]

Note the behaviour if you don't pass an actual list, it assumes you want a list regardless, one containing just the single item.


If you don't want to construct a flattened list, you can just use a similar method to get the count of any item in the list of lists, with something like:

def deepCount(listOrItem, searchFor):
    if type(listOrItem) != type([]): # Non-list, one only if equal.
        return 1 if listOrItem == searchFor else 0

    subCount = 0                     # List, recursively collect each count.
    for item in listOrItem:
        subCount += deepCount(item, searchFor)
    return subCount

deepList = [[1,2],[3,'a'],[5,[6,7,[8,9]]],[10,'a',[11,[12,13,14]]]]
print(f'Count of "a" is {deepCount(deepList, "a")}')
print(f'Count of 13  is {deepCount(deepList, 13)}')
print(f'Count of 99  is {deepCount(deepList, 99)}')

As expected, the output of this is:

Count of "a" is 2
Count of 13  is 1
Count of 99  is 0

(a) Up to the limits imposed by Python itself of course, limits you can increase by just adding this to the top of your code:

import sys
sys.setrecursionlimit(1001) # I believe default is 1000.

I mention that just in case you have some spectacularly deeply nested structures but you shouldn't really need it. If you're nesting that deeply then you're probably doing something wrong :-)

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953