How do I move list elements to another list if a condition is met?

Question:

I have a list of values and I want to move certain (or all) values to another list if they exist in a reference list.

x = [2,3,4,5,6,7,8] # list of values
ref = [2,3,4,5,6,7,8] # reference list
result = [x.pop(i) for i, v in enumerate(x) if v in ref]

But because of popping the current index, it ends up giving every other value instead. Is there a nice straightforward way to do this?

What I want at the end of this example is x=[] and result=[2,3,4,5,6,7,8], but ref doesn’t need to contain all elements of x, this was just for an example. In another case it might be:

x = [2,3,4,5,6,7,8] # list of values
ref = [2,6,7] # reference list

So then I want x = [3,4,5,8] and result = [2,6,7]

Asked By: crabulus_maximus

||

Answers:

This works, but it’s a bit long.

x = [2,3,4,5,6,7,8] # list of values
ref = [2,3,4,5,6,7,8] # reference list
result = []
for i in x:
    if i in ref:
        result.append(i)
Answered By: da_picklechin

You could do it the old-fashioned way, with a while loop and a pointer into x:

x = [2, 3, 4, 5, 6, 7, 8]
ref = [2, 6, 7]

result = []
i = 0
while i < len(x):
    if x[i] in ref:
        result.append(x.pop(i))
    else:
        i += 1

print(x)
print(result)

Output:

[]
[2, 3, 4, 5, 6, 7, 8]
Answered By: wjandrea

You can simply iterate from the end to the start to avoid pop() changing the list size while iterating. Just call reverse() on your new list after running your loop if the order of the list matters.

Answered By: Jesse

In general, we should avoid modifying objects while iterating over them.

For this problem, we could generate result and filter x in two steps using comprehensions (avoiding appending to lists) as in the following example.

result, x = [v for v in x if v in ref], [v for v in x if v not in ref]
Answered By: Richard Ambler
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.