Neemaximo
Neemaximo

Reputation: 20771

Remove empty nested lists within list

See below for the exact code. Basically, I am trying to take information from a csv file and create a list with one of the columns that has all the usernames (with no blanks or duplicates). I am able to get a list of all the usernames, but I can not find a way to remove the blanks. I have tried both filter as well as other methods, but can't seem to get it right. My code is:

with open('test.csv') as f:
reader = csv.DictReader(f)
initialExport = []
for row in reader:
    iE = [row['Computer Name'], row['Username']]
    initialExport.append(iE)

for i in initialExport:
    i.pop(0)
finalExport = filter(None, initialExport)
print(finalExport)

Upvotes: 0

Views: 1048

Answers (4)

TemporalWolf
TemporalWolf

Reputation: 7952

purge(list, [elements to purge]) will recursively purge all copies of element from the list and any sublists, including any elements created by removing deeper elements ([[[], []]] will be entirely removed). Because we're modifying the list in-place, we have to restart at our current depth every time we remove an element:

def purge(lst, bad):
    restart = True
    while restart:
        restart = False
        for index, ele in enumerate(lst[:]):
            if ele in bad:
                del lst[index]
                restart = True
                break
            elif isinstance(ele, list):
                purge(ele, bad)
                if lst[index] in bad:
                    del lst[index]
                    restart = True
                    break

Examples:

>>> lst = [[[[], [[],[]]]]]
>>> purge(lst, [[]])
[]

>>> lst = [1, 2, "3", "three", [], [1, 2, "3"], [[], []], 4,
       [[1], []], [[], [], []], 5, "6", (1,2), 7, [[[]]]]
>>> purge(lst, [[]])
[1, 2, '3', 'three', [1, 2, '3'], 4, [[1]], 5, '6', (1, 2), 7]
>>> purge(lst, ['3'])
[1, 2, 'three', [1, 2], 4, [[1]], 5, '6', (1, 2), 7]

Upvotes: 0

Spherical Cowboy
Spherical Cowboy

Reputation: 566

This shows a way to remove empty lists, empty tuples and lists containing only empty lists from lst. The code below will not remove:

  • empty nested tuples (with one or more levels)
  • empty nested lists with more than two levels

Confer the last two entries of lst.

import collections

lst = [1, 2, "3", "three", [], [1, 2, "3"], [[], []], 4,
       [[1], []], [[], [], []], 5, "6", (1,2), 7, (),
       ((), ()), [[[]]]]

for index, item in enumerate(lst):
    # if it is an empty list [] or tuple ()
    if not item:
        del lst[index]
    # if it is a list containing only empty sublists [[], [], ...]
    elif isinstance(item, collections.MutableSequence):
        if not [i for sublist in item for i in sublist]:
            del lst[index]

print(lst)

Output:

[1, 2, '3', 'three', [1, 2, '3'], 4, [[1], []], 5, '6', (1, 2), 7, ((), ()), [[[]]]]

Four elements are removed from lst in the above example, namely [], [[], []], [[], [], []] and ().

Upvotes: 0

user2390182
user2390182

Reputation: 73450

initialExport is a list of (singleton) lists when you try to filter them. Some of these lists might contain the empty string. That does not make them empty lists! So their truthiness is true no matter what. You could filter them out via:

finalExport =  [l for l in initialExport if l[0]]

But why add the Computer Name column in the first place if you just pop it? And why make a nested list if you are just interested in one element:

finalExport = [row['Username'] for row in reader if row['Username']]

Upvotes: 1

daveruinseverything
daveruinseverything

Reputation: 5167

Rather than filtering it out, why not just avoid adding blank entries in the first place:

for row in reader:
    if row['Username']:
        iE = [row['Computer Name'], row['Username']]
        initialExport.append(iE)

Upvotes: 1

Related Questions