Home > Mobile >  removing sublists which contain empty sublists only at specific positions
removing sublists which contain empty sublists only at specific positions

Time:04-14

Consider the list:

list_1 = [
    [
        [1, 2, 3], [], [3, 4, 5], [], [4, 5, 6], [7, 8, 9], [9, 1, 0]
    ],
    [
        [0, 1, 2], [9, 0, 1], [], [0, 1, 3], [1, 1, 1], [9, 5, 6], [3, 6, 7]
    ],
    [
        [1, 2, 4], [4, 5, 6], [], [1, 0, 1], [0, 1, 1], [3, 9, 7], []
    ],
    [
        [1, 3, 4], [], [3, 5, 6], [], [], [], [0, 7, 0]
    ]
]

I want to remove a row if it contains empty list either at 1st , 3rd or 7th position.

For example above the 2nd and 3rd rows must be removed. I tried this:

list_2 = [sublist for sublist in list_1 if all(x for x in sublist)]

How I call the index 1, 3, 7 in this?

CodePudding user response:

Using filter and list slicing with operator.itemgetter.

NB. as your lists have 7 elements and python indexing starts at 0, I assumed you mean elements 0, 2, 6

from operator import itemgetter
list_2 = list(filter(lambda l: [] not in itemgetter(0,2,6)(l), list_1))

output:

[[[1, 2, 3], [], [3, 4, 5], [], [4, 5, 6], [7, 8, 9], [9, 1, 0]],
 [[1, 3, 4], [], [3, 5, 6], [], [], [], [0, 7, 0]]]

CodePudding user response:

This should work.

Method 1

The outer loop loops over the elements ('row's) of list_2 whereas the inner loop, for some fixed element of list_2 loops over the elements of that element of list_2 until it finds an empty list in the required position and then breaks from the inner loop so that we move onto another element ('row') of list_2. Before the break, the list_2 index that is in place is stored in the delete_indices list. After the loop is done, we use delete_indices to decide which rows to keep.

indices = (0, 2, 6)
delete_indices = []
for idx_x, x in enumerate(list_1):
    for idx_y, y in enumerate(x):
        if idx_y in indices and not y:
            delete_indices.append(idx_x)
            break

list_2 = [x for idx, x in enumerate(list_1) if idx not in delete_indices]

Output

[[[1, 2, 3], [], [3, 4, 5], [], [4, 5, 6], [7, 8, 9], [9, 1, 0]],
 [[1, 3, 4], [], [3, 5, 6], [], [], [], [0, 7, 0]]]

Method 2 follows a similar logic to method 1 and is faster than method 1 (see below).

def pred(l: list, indices = (0, 2, 6)):
    for idx, item in enumerate(l):
        if not item and idx in indices:
            return True
    return False

list_2 = [item for item in list_1 if not pred(item)]

Comparison

Efficiency-wise, you should prefer @mozway's way.

# mozway's way (no rhymes intended)
908 ns ± 2.87 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
# Method 2 
1.4 µs ± 2.53 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
# Method 1 
1.78 µs ± 20.5 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
  • Related