Python numpy fill masked elements in matrix according to order in another matrix
Question: I'm trying to do a Uniform Order Crossover for a genetic algorithm. In that, I
have two 2D arrays p1 and p2 and a 2D bit array, b. p1, p2 and b are of the
same shape. I mask elements in p1 corresponding to 1s in b and elements in p2
corresponding to 0s in b. From these, I need to generate 2 matrices c1 and c2
such that c1 has the same elements as in p2 but has the blanks replaced by the
corresponding values in p2 as per the order given in p1 and the opposite for
c1.

For example:

    
    
    p1 = [[1, 2, 3, 4, 5],
          [1, 4, 3, 2, 5]]
    p2 = [[5, 4, 3, 2, 1],
          [2, 1, 3, 4, 5]]
    b = [[1, 0, 1, 0, 1],
         [1, 0, 0, 1, 0]]
    

masked arrays are mp1 and mp2;

    
    
    mp1 = [[1, _, 3, _, 5],
           [1, _, _, 2, _]]
    mp2 = [[_, 4, _, 2, _],
           [_, 1, 3, _, 5]]
    

Then c1 and c2 would be,

    
    
    c1 = [[1, 4, 3, 2, 5],
          [1, 3, 4, 2, 5]]
    c2 = [[1, 4, 3, 2, 5],
          [4, 1, 3, 2, 5]]
    

p1, p2, b, c1, c2 are of dimension 500X100000 in my case, so the answer needs
to be vectorized and efficient.


Answer: I can't exactly make sense of what exactly you're asking, because either you
have made a typo in your question or I'm just completely missing the point
here.

So, first we have a mask for p1

    
    
    mp1 = [[1, _, 3, _, 5],
           [1, _, _, 2, _]]
    

where the `_` values should be replaced by corresponding values from p2. Which
should be

    
    
    [[_, 4, _, 2, _],
     [_, 1, 3, _, 5]]
    

so in my head the result should be

    
    
    [[1, 4, 3, 2, 5],
     [1, 1, 3, 2, 5]])
    

but you say the expected result is

    
    
    [[1, 4, 3, 2, 5],
     [1, 3, 4, 2, 5]]
    

how does 3 appear there and where does the 4 come from? What am I missing?
(Before anyone holds this against me, I can't fit this in a comment)

If you can use `numpy`, and for stuff like this I recommend you do, the
solution, to the best of my interpretation abilities, would be:

    
    
    p1 = [[1, 2, 3, 4, 5],
          [1, 4, 3, 2, 5]]
    p2 = [[5, 4, 3, 2, 1],
          [2, 1, 3, 4, 5]]
    b = [[1, 0, 1, 0, 1],
         [1, 0, 0, 1, 0]]
    
    #this is just how you turn python lists into numpy arrays
    import numpy as np
    p1 = np.asarray(p1)
    p2 = np.asarray(p2)
    b = np.asarray(b)
    
    #this is the actual solution to the problem
    p1[b==0] = p2[b==0]
    

These substitutions are done in place, so it's nice for the memory and they're
basically done in the background in C which means it's lightning fast.

