Nested List and count()

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.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

>>> L = [[1, 2, 3], [1, 1, 1]]
>>> sum(x.count(1) for x in L)
4

Method 2

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

Method 3

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

Method 4

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!

Method 5

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
>>>

Method 6

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

Method 7

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

Method 8

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 🙂


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x