Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

merging two python lists with boolean mask [duplicate]

Tags:

python

I have a simple python list and a boolean mask. First that list is separated out into two lists based on the mask, and then I want to combine those two lists back into the original list, without copying/emptying the two lists (which rules out using .pop() or .copy()). Simple enough to implement in pandas, np, or long-winded code. However, I need to implement it in lists; no extra libraries possible (something like itertools would be ok).

Question: How can I combine two lists with a mask cleanly, without clutter and without np/pandas/etc?

Minimum example:

# some data
x = [1.0,2.0,3.0,4.0]
print('original list: {}'.format(x))
# a boolean mask
mask = [True,False,False,True]
print('boolean mask: {}'.format(mask))
# splitting based on the mask is easy enough
xt = [xx for (xx,m) in zip(x,mask) if m]
xf = [xx for (xx,m) in zip(x,mask) if not(m)]
print('true mask of x: {}'.format(xt))
print('false mask of x: {}'.format(xf))

# --output--
# original list: [1.0, 2.0, 3.0, 4.0]
# boolean mask: [True, False, False, True]
# true mask of x: [1.0, 4.0]
# false mask of x: [2.0, 3.0]

Now combine them; the problem I want to solve. Here are three ways that work but are disqualified (first is clunky, second uses np, third empties xt and xf):

# Method 1: desired performance, but long-winded
i=0
j=0
x_merge=[]
for m in mask:
    if m: 
        x_merge.append(xt[i])
        i += 1
    else:
        x_merge.append(xf[j])
        j += 1
print('merging back together (clunky): {}'.format(x_merge))

# Method 2: in numpy it's not hard either
import numpy as np
x_merge2 = np.zeros(len(xt)+len(xf))
x_merge2[mask]=xt
x_merge2[[not(m) for m in mask]]=xf
print('merging back together (np): {}'.format(x_merge2))

# Method 3: clean, but empties xt and xf, which I can't do; copy/pop also no good
x_merge3 = [xt.pop(0) if m else xf.pop(0) for m in mask]
print('merging back together (pop): {}'.format(x_merge3))

# --output--
# merging back together (clunky): [1.0, 2.0, 3.0, 4.0]
# merging back together (np): [1. 2. 3. 4.]
# merging back together (pop): [1.0, 2.0, 3.0, 4.0]

This feels simple enough to achieve but a bit tricky without copy/pop, pd,np, or similar (which is a real requirement based on the type constraints in the surrounding code; I can't cast it back to a list or anything like that). Can someone tell me how to do this right?

Edit: I searched so before posting (without luck) but yes the answer is contained within this post: Merge two or more lists with given order of merging.

like image 307
muskrat Avatar asked Dec 12 '25 17:12

muskrat


1 Answers

Method 3, but with standard iterators instead of popping.

xti, xfi= iter(xt), iter(xf)
merged = [next(xti) if m else next(xfi) for m in mask]

(xti.next() will work, but only in python2)

like image 77
Green Cloak Guy Avatar answered Dec 15 '25 05:12

Green Cloak Guy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!