Replacing elements in lists of a nested list

I have the following nested list

CombiningCyclesCase2={{1, 2, 3, 0, 0}, {1, 2, 4, 3, 0}, {1, 2, 4, 5, 3}, {3, 2, 1, 4, 0}, {3, 2, 1, 5, 4}, {3, 2, 4, 1, 5}, {3, 4, 1, 2, 5}, {3, 2, 4, 5, 1}, {3, 5, 4, 1, 2}}


I want to replace the zeroes in the sublists that have zeroes, by the corresponding position of the zeroes. For instance, in the sublist {1,2,3,0,0} I want to replace the 0's to have {1,2,3,4,5}, but in the sublists that don't have any zeros, I want to leave them like they are. I tried doing this with the following line of code, where n=5:

n = 5;
Table[If[Max[CombiningCyclesCase2[[i]]] == n,
CombiningCyclesCase2[[i]]],
ReplacePart[CombiningCyclesCase2[[i]],
Range[Max[CombiningCyclesCase2[[i]]] + 1, n]], {i,
Length[CombiningCyclesCase2]}]


However, I get the error Part::pkspec1: The expression i cannot be used as a part specification. >>. Does anyone have a suggestion on how to solve this problem or if there is an easier way to do this?

• Are you the same as cesar? If so, you can talk to the moderators to get your two accounts merged. Commented Jun 27, 2016 at 3:38

One solution:

MapIndexed[If[# == 0, Last[#2], #] &, CombiningCyclesCase2, {2}]

ClearAll[f]
f = ReplacePart[#, # -> Last @# & /@ Position[#, 0]]&;

f @ CombiningCyclesCase2


If your lists are large (and rectangular as your example), this s/b considerably faster than existing answers:

fix=With[{d=Dimensions@#},#+BitXor[1,Unitize@#]*ConstantArray[Range@d[[2]],d[[1]]]]&;


or simpler and similar speed:

fix2=With[{rx = Range@Length@#[[1]]}, (# + BitXor[1, Unitize[#]]*rx) & /@ #] &;

– yode
Commented Jun 26, 2016 at 8:33
fun:=(1-Unitize[#])*Range[Length@#]+#&


Usage

fun/@CombiningCyclesCase2


{{1,2,3,4,5},{1,2,4,3,5},{1,2,4,5,3},{3,2,1,4,5},{3,2,1,5,4},{3,2,4,1,5},{3,4,1,2,5},{3,2,4,5,1},{3,5,4,1,2}}

foo[x_] := ReplacePart[i_ :> If[x[[i]] == 0, i, x[[i]]]] @ x

foo /@ CombiningCyclesCase2


{{1, 2, 3, 4, 5}, {1, 2, 4, 3, 5}, {1, 2, 4, 5, 3}, {3, 2, 1, 4, 5}, {3, 2, 1, 5, 4}, {3, 2, 4, 1, 5}, {3, 4, 1, 2, 5}, {3, 2, 4, 5, 1}, {3, 5, 4, 1, 2}}

Another way to do this using Delete, Partition and Riffle:

f[l_] := Map[Apply[Join, #] &,
Partition[
Riffle[Function[Delete[#, Position[#, 0]]][l],
Map[Function @ Complement[Range @ Last @ Dimensions @ #, #], l]
],
{2}
]
];


Test:

f@CombiningCyclesCase2

(*{{1, 2, 3, 4, 5}, {1, 2, 4, 3, 5}, {1, 2, 4, 5, 3}, {3, 2, 1, 4, 5},
{3, 2, 1, 5, 4}, {3, 2, 4, 1, 5}, {3, 4, 1, 2, 5}, {3, 2, 4, 5, 1}, {3, 5, 4, 1, 2}}*)

• You can think about removing the MatrixQ restriction.
– Syed
Commented Sep 14, 2023 at 3:26
list = {
{1, 2, 3, 0, 0}, {1, 2, 4, 3, 0}, {1, 2, 4, 5, 3},
{3, 2, 1, 4, 0}, {3, 2, 1, 5, 4}, {3, 2, 4, 1, 5},
{3, 4, 1, 2, 5}, {3, 2, 4, 5, 1}, {3, 5, 4, 1, 2}};


Using SubsetMap (new in 12.0)

f[x_] := With[{p = Flatten @ Position[x, 0]}, SubsetMap[p &, x, p]]

f /@ list


{{1, 2, 3, 4, 5}, {1, 2, 4, 3, 5}, {1, 2, 4, 5, 3}, {3, 2, 1, 4, 5}, {3, 2, 1, 5, 4}, {3, 2, 4, 1, 5}, {3, 4, 1, 2, 5}, {3, 2, 4, 5, 1}, {3, 5, 4, 1, 2}}

MapIndexed was designed to handle such problems. However, in the interest of computational diversity, let's use MapThread with PositionIndex. I have added a slightly longer sublist for testing and taken some liberty with output styles.

Clear["Global*"];
CombiningCyclesCase2 = {{1, 2, 3, 0, 0}, {1, 2, 4, 3, 0}, {1, 2, 4, 5,
3}, {3, 2, 1, 4, 0}, {3, 2, 1, 5, 4}, {3, 2, 4, 1, 5}, {3, 4, 1,
2, 5}, {0, 11, 0, 11, 0, 11, 0, 11}, {3, 2, 4, 5, 1}, {3, 5, 4, 1,
2}};

reps = PositionIndex[#][0] & /@
CombiningCyclesCase2 /. {Missing[__] :> {},
a_Integer :> a -> Style[a, Red]}

`