How to store only not empty string from dictionary and store them in a list with a for loop?

Viewed 77

Maybe it's a silly question but I'm really stuck on this one. I have a dictionary of string, I extract all string from the key avis_technique but I don't know how to store each string into a single list and remove all empty string.

    for material in materials['materials']:
        avis_tech = material['details'].get('avis_technique')
        urls = avis_tech.split(', ')
        print(urls)

Currently my output I something like this:

['']
['']
['']
['']
['http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf']
['http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf']
['http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf']
['http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf']
['http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf']
['http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf']
['http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf']
['http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf']
['http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf']
['']
['']
['']
['']
['']

My goal is to have:

['http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf','http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf','http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf','http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf','http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf','http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf','http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf','http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf','http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf']
6 Answers

You can use if statement to check if url is an empty string. empty strings would always return false. E.G

a =''
if a:print(True)
else:print(False)

output

False
 for material in materials['materials']:
        avis_tech = material['details'].get('avis_technique')
        urls = [x for x in avis_tech.split(', ') if x]
        print(urls)

or

urls_list= []
 for material in materials['materials']:
        avis_tech = material['details'].get('avis_technique')
        urls=avis_tech.split(', ')
        if urls:
            urls_list.append(urls)

Try the following code: Where you declare an empty list at the start and append data to it during the loop:

final_urls = []
for material in materials['materials']:
    avis_tech = material['details'].get('avis_technique')
    urls = avis_tech.split(', ')
    final_urls += [url for url in urls if len(url) > 0 ]
    

You are creating a new list in every iteration of you loop. To put all Strings in one list, initialize an empty list before the loop and only add Strings that are not empty:


urls = []
for material in materials['materials']:
        avis_tech = material['details'].get('avis_technique')
        url = avis_tech.split(', ')
        (urls.append(url) if url is not None or len(url) > 0 else None)
print(urls)

I am assuming that you have a list of lists with all the urls and the empty strings and you want a flattened list of only the urls. You could flatten the list and then remove the empty elements likewise:

#Assuming the output you have of the list of list of urls is named "urls" 
final_list = [x for sublist in urls for x in sublist]

Removing empty strings:

final_list = [x for x in final_list if x]

Using functools.reduce:

from functools import reduce

urls = ['','','','',
'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf',
'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf',
'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf',
'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf',
'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf',
'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf',
'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf',
'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf',
'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf','','','','','']

def keep_if_not_empty(a, b):
    if len(b) > 0:
        a.append(b)
    return a

output = reduce(keep_if_not_empty, urls, [])

print(output)

Output:

['http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf', 'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf', 'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf', 'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf', 'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf', 'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf', 'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf', 'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf', 'http://www.cstb.fr/pdf/atec/GS20-U/AU21482_V1.pdf']

Info on the reduce function here.

Clean code using generators:

from itertools import chain

# generator of urls lists, e.g (['url_1', ''], ['', 'url_2'])
urls_lists = (
    x['details'].get('avis_technique', '').split(',')
    for x in materials['materials']
)
# we need to flatten the list and filter empty strings
urls = list(filter(bool, chain.from_iterable(urls_lists)))

I also believe that you have empty strings because of splitting an empty string (''.split(',') will result to ['']). If so, the above code can be simplified to

from itertools import chain

urls = list(chain.from_iterable(
    x['details']['avis_technique'].split(',')
    for x in materials['materials']
    if x['details'].get('avis_technique')
))
Related