# Rearrange a list according to position association with a new list

I have the following code:

l1 = {{1, 2, 3, 4}, {1, 2, 3}, {1, 2, 3, 4, 5}};
assoc = {{{1, 1}, {2, 2}, {3, 0}, {4, 3}, {5, 4}, {6, 0}}, {{1,
1}, {2, 0}, {3, 0}, {4, 2}, {5, 3}, {6, 0}}, {{1, 1}, {2, 0}, {3,
2}, {4, 3}, {5, 4}, {6, 5}}};
l2 = ConstantArray[0, {3, 6}];
Function[{u, v, w}, If[#2 > 0, v[[#1]] = u[[#2]]] & @@@ w], {l1, l2,
assoc}];
TableForm@Transpose@%


The goal is to rearrange the l1 so according to the assoc which works as follows e.g. for l1[[1]]: l1[[1,1;;2]] will map to l2[[1,1;;2]], l1[[1,3;;4]] will map to l2[[1,4;;5]] and the rest of l2[[1]] will have zeros. So assoc[[All,All,1]] contains the positions is l2 and assoc[[All,All,2]] contains positions in l1 but if assoc[[All,All,2]]==0 then the appropriate position in l2 is left as zero.

The code above works to some point, it throws errors and instead of zeros, the result has Null values. What would be a nice and elegant way to do this (i am not necessarily requiring to keep the assoc array in the exact form, i am looking for a nice and easy way to rearrange an array according the rules explained above).

The goal is to transform the table that looks like (the values in l1 with padded zeros):

into one like this (l2):

Where the rules of what from l1 should go where in l2 are give in some fashion by saying some position in l1 should go to some other position in l2 (such as e.g. in assoc)

• The question is unclear. What do you mean by l1[[1, 1;;2]] will map to l2[[1, 1;;2]]? Are you referring to a general functional correspondence, or do you mean that those specific values of l1 should be replaced with the corresponding values of l2? It appears that what you want is MapAt. If you clarify the question and give a small example of input and output, you might find more help forthcoming. Feb 11, 2020 at 15:53
• @Shredderroy I tried to update the question. Not sure if it is a bit clearer now Feb 11, 2020 at 15:59

Break it up into two routines, to clarify. We don't need the first elements of the assoc tuples when done this way.

l1p = PadRight[#, 6] & /@ l1
(* {{1, 2, 3, 4, 0, 0}, {1, 2, 3, 0, 0, 0}, {1, 2, 3, 4, 5, 0}} *)


This takes a row of l1p and a row of assoc

set[l1r_, assocr_] := Map[If[# != 0, l1r[[#]], 0] &, assocr[[All, 2]] ]


Then MapThread this over l1p and assoc

l2 = MapThread[set, {l1p, assoc}]
(* {{1, 2, 0, 3, 4, 0}, {1, 0, 0, 2, 3, 0}, {1, 0, 2, 3, 4, 5}} *)


Transposed

$$\left( \begin{array}{ccc} 1 & 1 & 1 \\ 2 & 0 & 0 \\ 0 & 0 & 2 \\ 3 & 2 & 3 \\ 4 & 3 & 4 \\ 0 & 0 & 5 \\ \end{array} \right)$$

• You way works. But is there a more general approach to such a problem that works on an arbitrary level of lists? It is basically a permutation problem but extended in the sense that you fill in the non-filled positions with zeros (or something)) Feb 11, 2020 at 19:19
• I'm sure there is, but your problem was really just dealing with a row of l1 three times. No coupling between the rows. If you were assigning an element in one row based on an element in another row, then it gets more complicated. Maybe you can post a more complex problem. Feb 11, 2020 at 19:37

You can use SparseArray using Position[assoc, {_, Except@0}] as the non-zero positions and Join @@ l1 as the non-zero values:

l2 = SparseArray[Position[assoc, {_, Except@0}] -> Join @@ l1];

TeXForm @ Row[MatrixForm /@ Transpose /@ {PadRight[l1, {Automatic, 6}], l2}, Spacer[10]]


$$\left( \begin{array}{ccc} 1 & 1 & 1 \\ 2 & 2 & 2 \\ 3 & 3 & 3 \\ 4 & 0 & 4 \\ 0 & 0 & 5 \\ 0 & 0 & 0 \\ \end{array} \right)\left( \begin{array}{ccc} 1 & 1 & 1 \\ 2 & 0 & 0 \\ 0 & 0 & 2 \\ 3 & 2 & 3 \\ 4 & 3 & 4 \\ 0 & 0 & 5 \\ \end{array} \right)$$

l2b = MapIndexed[# /. x_?Positive :> l1[[#2[[1]], x]] &, assoc[[All, All, -1]]];