Reputation: 29
I have python list like below
x = [False, 44, 3, 56, 3, [33, 45, 66, 3], ('c', 3), [4, 3]]*4
I want to count '3' , how many time its in this list, I have tried with for loop but it not count in side the another list and tuple, How to do it ?
expected output is 20.
Upvotes: 0
Views: 996
Reputation: 42143
You should probably check for types list and tuple specifically. Otherwise you won't properly count strings in the multi-level list.
here's a small recursive function that will do it:
x = [False, 44, 3, 56, 3, [33, 45, 66, 3], ('c', 3), [4, 3]]*4
def deepcount(value,target):
if not isinstance(value,(list,tuple)):
return int(value==target)
return sum(deepcount(v,target) for v in value)
print(deepcount(x,3)) # 20
it will properly count strings in the structure:
y = ["abc", 12, "a",[23, False,"abc"]]*3
print(deepcount(y,"abc")) # 6
print(deepcount(y,"a")) # 3
Upvotes: 0
Reputation: 13106
You can check if an object is iterable by using the hasattr(obj, '__iter__')
call
x = [False, 44, 3, 56, 3, [33, 45, 66, 3], ('c', 3), [4, 3]]*4
threes = 0
for item in x:
# object is iterable, iterate over it
if hasattr(item '__iter__'):
for sub_item in item:
if sub_item==3:
threes +=1
# otherwise it isn't, go ahead and do an equality check
elif item==3:
threes +=1
threes
20
To make this a recursive solution similar to others that are posted, be wary of hasattr(obj, '__iter__')
, as for str
types this will lead to infinite recursion. To avoid this:
def count_threes(x):
count = 0
for item in x:
if isinstance(item, str) or isinstance(item, bytes):
continue # skip to avoid infinite recursion
if hasattr(item, '__iter__'): # is an iterable
count += count_threes(item)
elif item == 3:
count += 1
return count
count_threes(x)
20
Upvotes: 0
Reputation: 39042
You can first flatten your irregular list using this method and then apply count(3)
from collections import Iterable, Counter
x = [False, 44, 3, 56, 3, [33, 45, 66, 3], ('c', 3), [4, 3]]*4
def flatten(l):
for el in l:
if isinstance(el, Iterable) and not isinstance(el, (str, bytes)):
yield from flatten(el)
else:
yield el
freqs = list(flatten(x)).count(3)
# 20
For reasons pointed out again by @bhlsing below, you can just iterate through the list ad count the occurrences of 3 and sum
sum(1 for i in flatten(x) if i == 3)
Alternatively You can also use Counter
if you want the frequency of all elements. For a single element, this would be an overkill as pointed out by @bhlsing
freqs = Counter(flatten(x))
print (freqs[3])
Upvotes: 3
Reputation: 161
In this solution, you just check every list and search for 3 in it
x = [False, 44, 3, 56, 3, [33, 45, 66, 3], ('c', 3), [4, 3]]*4
counter = 0
stash = []
stash.append(x)
while len(stash)!=0:
print(stash)
list = stash[0]
for element in list:
if hasattr(element, '__iter__') and not isinstance(element, str):
stash.append(element)
if element == 3:
counter += 1
stash.remove(list)
print(counter)
`
Upvotes: 0
Reputation: 44043
One of many ways:
def flatten(*args):
for x in args:
if isinstance(x, (list, tuple)):
for y in flatten(*x):
yield y
else:
yield x
x = [False, 44, 3, 56, 3, [33, 45, 66, 3], ('c', 3), [4, 3]]*4
print(len(list(filter(lambda x: x == 3, flatten(x)))))
Upvotes: 0
Reputation: 7812
Function:
def count_element(obj, el):
occurences = 0
for item in obj:
if isinstance(item, (list, tuple, set)):
occurences += count_element(item, el)
elif isinstance(item, type(el)):
occurences += int(item == el)
return occurences
Usage:
x = [False, 44, 3, 56, 3, [33, 45, 66, 3], ('c', 3), [4, 3]] * 4
count = count_element(x, 3)
Output:
20
Upvotes: 0
Reputation: 24691
Slow, hacky implementation of recursive count:
def recursive_count(lst, item):
count = 0
for elem in lst:
if elem == item:
count += 1
elif type(elem) in (list, dict, set, tuple): # or something else to check for iterale types
count += recursive_count(elem, item)
return count
Upvotes: 0