title: Mapping z's in numpy array A = [[x0, y0, z0], [x1, y1, z1]] for 3rd column of array B = [[x1, y1, ?], [x0, y0, ?]] based off matching (x,y)?
body: <p>I have a numpy array <code>T</code> whose rows have the following column structure: <code>[x, y, value]</code>, where x, y, value are integers. A sample <code>T</code> array would look like:</p>
  <pre><code>[[1, 0, 4],
   [0, 2, 3],
   [1, 2, 7]]
  </code></pre>
  <p>This data comes from a model where the third column specifies the value of a variable for the tuple <code>(x, y)</code>. In the model, this tuple corresponds to a label for the value. For example, my label <code>T_10</code> (subscript <code>10</code>) has value <code>4</code>, <code>T_02</code> has value <code>3</code> and <code>T_12</code> has value <code>7</code>.</p>
  <p>Now, I want to swap a pair of labels. For example, I want to replace all labels <code>2</code> with <code>1</code> (and vice versa), to get <code>T_20</code>, <code>T_01</code> and <code>T_21</code> for the previous examples respectively. So, this new data is</p>
  <pre><code>U = [[2, 0, ?],
       [0, 1, ?],
       [2, 1, ?]]
  </code></pre>
  <p>My issue is that I do not know how to make my new data look like this:</p>
  <pre><code>U = [[2, 0, -3]
       [0, 1, -4],
       [2, 1, -7]]
  </code></pre>
  <p>This new data should follow <strong>two rules</strong>:</p>
  <p><strong>First</strong>, it should correctly identify the row of <code>T</code> whose first and second columns <code>(x, y)</code> are the same as the new <code>(x, y)</code> in <code>U</code>. For each row of <code>U</code>, if the ordered pair <code>(x, y) = (x, y)</code> of <code>T</code>, then the appropriate '?' value  in the third column of <code>U</code> should be the corresponding value in <code>T</code>.</p>
  <p><strong>Second</strong>: If, on the other hand, <code>(x, y)</code> of <code>U = (y, x)</code> of <code>T</code>, then it should be the negative of the corresponding <code>value</code>.</p>
  <p>My attempt involved first extracting the columns of <code>T</code>, and then swapping the pair of labels using the following function:</p>
  <pre><code>def swap_indices(a, pair):
      for n, i in enumerate(a):
          if i == pair[0]: # check whether a0's element is = swap element 1
              a[n] = pair[1]
          elif i == pair[1]: 
              a[n] = pair[0]
      return a 
  </code></pre>
  <p>For example, I will swap label <code>0</code> with <code>1</code> and vice versa for column <code>x</code> and column <code>y</code> using:</p>
  <pre><code>pair = (0, 1)
  a0 = swap_indices(T[:,0], pair) # column x  
  a1 = swap_indices(T[:,1], pair) # column y 
  </code></pre>
  <p>Then I iterate over the number of rows of <code>T</code>; <code>num_rows_of_T</code>:</p>
  <pre><code>for k in range(num_rows_of_T):
      temp = np.where((T[k, 0] == a0[k]) &amp; (T[k, 1] == a1[k]) | ((T[k, 0] == a1[k]) &amp; (T[k, 1] == a0[k])))
  </code></pre>
  <p>Above, I am trying to get the index of the row where either <code>(x, y)</code> of <code>U</code> = <code>(x, y)</code> of <code>T</code>, or <code>(x, y)</code> of <code>U = (y, x)</code> of <code>T</code>. However this is where I get stuck. I don't think the above is correct. Also, this approach will not let me apply the <strong>second rule</strong> where I take the negative of the value of <code>T</code> if <code>(x, y) = (y, x)</code>. I also tried using <code>set()</code> for starters (to get an unordered pair), but I cannot correctly find the corresponding value of <code>T</code> even then.</p>
  <p>Basically, I want to find the <code>value</code>s of <code>T</code> that match with the new labels in <code>U</code>. My data is nice, in that there may only exist one possible set of coordinates, and that there is always a bijective mapping between the <code>(x,y)</code> of <code>T</code> and <code>U</code> (given my two rules).</p>
  <p>Any advice?
  Please help edit the question as necessary. It was very difficult for me to ask.</p>
  <p>Here is a minimal working example:</p>
  <pre><code>import numpy as np
  
  # swap index labels if match swap pair
  def swap_indices(a, pair):
      for n, i in enumerate(a):
          if i == pair[0]: # check whether a0's element is = swap element 1
              a[n] = pair[1]
          elif i == pair[1]: 
              a[n] = pair[0]
      return a
          
  def find_valid_swaps(The1 = np.array([1, 0, -1, 1, 0, 1]), headers = np.array(['10', '20', '21', '30', '31', '32'])):
   
      num_indices = len(The1)
      T = np.zeros((num_indices,3)); U = T;
      
      # match format given for T in question
      for i in range(num_indices):
          T[i,:] = [int(list(headers[i])[0]), int(list(headers[i])[1]), The1[i]]
      
      pair = (0, 1) # label pair to swap
      a0 = swap_indices(T[:, 0], pair) # column 0 of U
      a1 = swap_indices(T[:, 1], pair) # column 1 of U
      
      # try to extract correct 'value' from T based on new labels in U
      for k in range(num_indices):
          temp = np.where((T[k, 0] == a0[k]) &amp; (T[k, 1] == a1[k]) | ((T[k, 0] == a1[k]) &amp; (T[k, 1] == a0[k])))
          print(&quot;temp&quot;,temp[0][0])
          U[k, :] = [a0[k], a1[k], T[temp[0][0], 2]] # here, I would finally create the new U matrix, applying both rules
  
      print(U)
  
  find_valid_swaps()
  </code></pre>
  <p>More involved example using @MadPhysicist 's answer:</p>
  <pre><code># swap index labels if match swap pair
  def swap_indices(a, pair):
      for n, i in enumerate(a):
          if i == pair[0]: # check whether a0's element is = swap element 1
              a[n] = pair[1]
          elif i == pair[1]: 
              a[n] = pair[0]
      return a
      
  def key(arr, m):
      return arr[:, 0] * m + arr[:, 1]
      
  def find_valid_swaps(Thetas1 = np.array([1, 1, 0, 0, -1, -1]), Thetas2 = np.array([1, 0, -1, 1, 0, 1]), num_bands = 4, headers = np.array(['10', '20', '21', '30', '31', '32'])):
      
      import itertools # for permutations: https://stackoverflow.com/questions/40092474/get-all-pairwise-combinations-from-a-list
      
      if (Thetas1==Thetas2).all():
          print(&quot;Warning: Input sets of indices are equal to each other. Will check other possible permutations regardless.&quot;)
      else: 
          print(&quot;Input sets of indices are unique. Will proceed checking other viable permutations.&quot;)
  
      num_indices = len(Thetas1)
      
      T = np.zeros((num_indices,3))
      U = np.zeros((num_indices,3))
      
      for i in range(num_indices):
          T[i,:] = [int(list(headers[i])[0]), int(list(headers[i])[1]), Thetas2[i]]
      
      print(&quot;input T&quot;)
      print(T)
      
      pair = (2,3)
      a0 = swap_indices(T[:,0], pair) # column 1  
      a1 = swap_indices(T[:,1], pair) # column 2 
      
      
      for k in range(num_indices):
          U[k, :] = [a0[k], a1[k], 0] 
  
      # below code due to @MadPhysicist from https://stackoverflow.com/questions/67223782/mapping-zs-in-numpy-array-a-x0-y0-z0-x1-y1-z1-for-3rd-column-of-ar/67235030?noredirect=1#67235030
      
      y_max = T[:, 1].max() + 1
      Tkey = key(T, y_max)
      s = np.argsort(Tkey)
  
      Ukey = key(U, y_max)
      i = np.searchsorted(Tkey, Ukey, sorter=s)
      i[i == len(i)] -= 1  # cleanup indices that won't match anyway
      mask = (Ukey == Tkey[s[i]])
  
      U2key = key(U[~mask, 1::-1], y_max)
      j = np.searchsorted(Tkey, U2key, sorter=s)
     
      U[mask, -1] = T[s[i[mask]], -1]
      U[~mask, -1] = -T[s[j], -1]
      
      print(&quot;reordered U&quot;)
      print(U)
  </code></pre>
  <p>The above gives output:</p>
  <pre><code>input T
  [[ 1.,  0.,  1.]
   [ 2.,  0.,  0.]
   [ 2.,  1., -1.]
   [ 3.,  0.,  1.]
   [ 3.,  1.,  0.]
   [ 3.,  2.,  1.]]
  reordered U
  [[ 1.,  0.,  1.]
   [ 3.,  0.,  0.]
   [ 3.,  1., -1.]
   [ 2.,  0.,  1.]
   [ 2.,  1.,  0.]
   [ 2.,  3.,  1.]]
  </code></pre>