Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove sublist from list

Tags:

python

list

I want to do the following in Python:

A = [1, 2, 3, 4, 5, 6, 7, 7, 7]
C = A - [3, 4]  # Should be [1, 2, 5, 6, 7, 7, 7]
C = A - [4, 3]  # Should not be removing anything, because sequence 4, 3 is not found

So, I simply want to remove the first appearance of a sublist (as a sequence) from another list. How can I do that?

Edit: I am talking about lists, not sets. Which implies that ordering (sequence) of items matter (both in A and B), as well as duplicates.

like image 514
dimitris93 Avatar asked Apr 09 '18 16:04

dimitris93


People also ask

How do I remove a sublist from a list?

Using the subList() and the clear() methods The clear() method of List interface removes all the elements from the current List object.

How do I remove a sub list from a list in Python?

The remove() method removes the first matching element (which is passed as an argument) from the list. The pop() method removes an element at a given index, and will also return the removed item. You can also use the del keyword in Python to remove an element or slice from a list.

How do I remove a sublist from a nested list in Python?

Remove items from a Nested List. If you know the index of the item you want, you can use pop() method. It modifies the list and returns the removed item. If you don't need the removed value, use the del statement.


2 Answers

Use sets:

C = list(set(A) - set(B))

In case you want to mantain duplicates and/or oder:

filter_set = set(B)
C = [x for x in A if x not in filter_set]
like image 57
Netwave Avatar answered Sep 22 '22 15:09

Netwave


If you want to remove exact sequences, here is one way:

Find the bad indices by checking to see if the sublist matches the desired sequence:

bad_ind = [range(i,i+len(B)) for i,x in enumerate(A) if A[i:i+len(B)] == B]
print(bad_ind)
#[[2, 3]]

Since this returns a list of lists, flatten it and turn it into a set:

bad_ind_set = set([item for sublist in bad_ind for item in sublist])
print(bad_ind_set)
#set([2, 3])

Now use this set to filter your original list, by index:

C = [x for i,x in enumerate(A) if i not in bad_ind_set]
print(C)
#[1, 2, 5, 6, 7, 7, 7]

The above bad_ind_set will remove all matches of the sequence. If you only want to remove the first match, it's even simpler. You just need the first element of bad_ind (no need to flatten the list):

bad_ind_set = set(bad_ind[0])

Update: Here is a way to find and remove the first matching sub-sequence using a short circuiting for loop. This will be faster because it will break out once the first match is found.

start_ind = None
for i in range(len(A)):
    if A[i:i+len(B)] == B:
        start_ind = i
        break

C = [x for i, x in enumerate(A) 
     if start_ind is None or not(start_ind <= i < (start_ind + len(B)))]
print(C)
#[1, 2, 5, 6, 7, 7, 7]
like image 27
pault Avatar answered Sep 24 '22 15:09

pault