'Iterating over nested list and count specific value
I have this nested list:
d = ['good morning', 'hello', 'chair', 'python', ['music', 'flowers',
'facebook', 'instagram', 'snapchat', ['On my Own', 'monster', 'Words
dont come so easily', 'lead me right']], 'Stressed Out', 'Pauver
Coeur', 'Reach for Tomorrow', 'mariners song', 'Wonder sleeps here']
I need to iterate through the list so that if the character ‘m’ is in the string, then it should be added to a new list called m_list
.
What I tried so far is the following:
m_list = []
for el in d:
print(" Level1: {}".format(el))
if type(el) is str:
if 'm' in el:
m_list.append(el)
for el2 in el:
print(" Level2: {}".format(el2))
if type(el2) is str:
if 'm' in el2:
m_list.append(el2)
for word in el2:
print(" Level3: {}".format(word))
if type(word) is str:
if 'm' in word:
m_list.append(word)
I know that I do not set up correctly the code because inner loop will double count some elements. As example here:
print(m_list)
['good morning', 'm', 'm', 'music', 'm', 'instagram', 'm', 'On my Own',
'monster', 'Words dont come so easily', 'lead me right', 'Reach for
Tomorrow', 'm', 'm', 'mariners song', 'm', 'm']
I solved this using this inefficient code:
s = set(m_list)
m_list = list(s)
m_list.remove('m')
print(m_list)
['monster', 'mariners song', 'Words dont come so easily', 'Reach for
Tomorrow', 'On my Own', 'lead me right', 'music', 'good morning',
'instagram']
My question how I can change for loop in order to work correctly to count character 'm' and assign to m_list?
P.S. I am not proficient user of Python. I would like to improve my skills. Would you like to suggest me smarter way to do it?
Solution 1:[1]
If you are not sure of the depth of your nesting then you need a recursive approach like this:
def find_char(char, words):
result = []
for word in words:
if isinstance(word,list):
result += find_char(char,word)
else:
if char in word:
result.append(word)
return result
>>> d = ['good morning', 'hello', 'chair', 'python', ['music', 'flowers',
'facebook', 'instagram', 'snapchat', ['On my Own', ['monster'], 'Words don`t come so easily', 'lead me right']], 'Stressed Out', 'Pauver Coeur', 'Reach for Tomorrow', 'mariners song', 'Wonder sleeps here']
>>> find_char("m",d)
['good morning', 'music', 'instagram', 'On my Own', 'monster', 'Words don`t come so easily', 'lead me right', 'Reach for Tomorrow', 'mariners song']
This will work no matter how deeply your list is nested.
Solution 2:[2]
You can create a generic custom function that calls itself if you have list within or appends the value to new list if it contains 'm'
in it:
d = ['good morning', 'hello', 'chair', 'python', ['music', 'flowers',
'facebook', 'instagram', 'snapchat', ['On my Own', 'monster', 'Words dont come so easily', 'lead me right']], 'Stressed Out', 'Pauver Coeur', 'Reach for Tomorrow', 'mariners song', 'Wonder sleeps here']
def find_all_values(d, m, m_list=[]):
for x in d:
if isinstance(x, list):
find_all_values(x, m, m_list)
elif m in x:
m_list.append(x)
return m_list
m_list = find_all_values(d, 'm')
# ['good morning', 'music', 'instagram', 'On my Own', 'monster', 'Words dont come so easily', 'lead me right', 'Reach for Tomorrow', 'mariners song']
m_list_count = len(m_list)
# 9
Now that you have a generic custom function, you can use this to create list that holds values containing any letter and get its count.
Solution 3:[3]
In Python 3:
def myflatten(l):
for elem in l:
if isinstance(elem, list):
yield from myflatten(elem)
else:
if 'm' in elem:
yield elem
list(myflatten(d))
Solution 4:[4]
You need to tell the inner for
loop not to run if the element is a string. There are two common ways that apply to your case:
Add an
else
clause to the precedingif
and indent thefor
loop. This translates into "run this code only if the element isn't a string":if type(el) is str: if 'm' in el: m_list.append(el) else: for el2 in el: ...
Add a
continue
statement if the element is a string. This translates to "don't do anything else if you have a string":if type(el) is str: if 'm' in el: m_list.append(el) continue for el2 in el:
Personally I like the first version because it is more explicit. At the same time, the second version saves you a level of indentation in the rest of your code, which can be very nice as well.
Solution 5:[5]
Try this:
m_list = []
for el in d:
if type(el) is str:
if 'm' in el:
m_list.append(el)
else:
for el2 in el:
if type(el2) is str:
if 'm' in el2:
m_list.append(el2)
else:
for word in el2:
if type(word) is str:
if 'm' in word:
m_list.append(word)
print(m_list)
Solution 6:[6]
Here is a recursive solution
data = ['good morning', 'hello', 'chair', 'python', ['music', 'flowers', 'facebook', 'instagram', 'snapchat',
['On my Own', 'monster', 'Words dont come so easily',
'lead me right']], 'Stressed Out', 'Pauver Coeur',
'Reach for Tomorrow', 'mariners song', 'Wonder sleeps here']
m_holder = []
def m_finder(lst, m_holder):
for word_or_list in lst:
if isinstance(word_or_list, str):
if 'm' in word_or_list:
m_holder.append(word_or_list)
else:
m_finder(word_or_list, m_holder)
m_finder(data, m_holder)
print(m_holder)
Output:
['good morning', 'music', 'instagram', 'On my Own', 'monster', 'Words dont come so easily', 'lead me right', 'Reach for Tomorrow', 'mariners song']
Solution 7:[7]
This is a very simple solution to your answer try this:
d = ['good morning', 'hello', 'chair', 'python', ['music', 'flowers',
'facebook', 'instagram', 'snapchat', ['On my Own', 'monster',
'Words dont come so easily', 'lead me right']], 'Stressed Out', 'Pauver Coeur',
'Reach for Tomorrow', 'mariners song', 'Wonder sleeps here']
m_list=[]
for v in d:
if 'm' in v:
m_list.append(v)
if type(v) is list:
for x in v:
if 'm' in x:
m_list.append(x)
if type(x)is list:
for y in x:
if 'm' in y:
m_list.append(y)
if type(y) is list:
for f in z:
if 'm' in f:
m_list.append(f)
print(m_list)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | BoarGules |
Solution 2 | |
Solution 3 | Davide Albanese |
Solution 4 | Mad Physicist |
Solution 5 | Heyran.rs |
Solution 6 | balderman |
Solution 7 | Emi OB |