Replacing elements at a single level in a nested list

I want to replace all instances of 0 in the outer most level of a nested list with 1. However, when I use ReplaceAll as

ReplaceAll[{{0, 0}, 0}, 0 -> 1]


it replaces all three zeros, rather than just the last one. What should I do to only replace the zeros in the outermost level? I will be using this on a much longer nested list so I don't want to refer to the specific positions of individual zeros.

Thanks in advance for any help.

Try

 Replace[{{0, 0}, 0}, 0 -> 1, {1}]

• What is the difference between this (levelspec as {1}) and the answer I proposed (levelspec as 1)?
– a20
Commented Dec 9, 2021 at 14:33
– dnet
Commented Dec 10, 2021 at 15:15

I am sure there are a hundred other solutions, but this one does the job and should be reasonably efficient:

In: Map[If[ListQ[#], #, Replace[#, 0 -> 1]] &, {{0, 0}, 0}]
Out: {{0,0},1}


Another better solution:

In: Replace[{{0, 0}, 0, 0, 0, {0, 0, 0}, {{0, 0}, 0}, 0, 0}, 0 -> 1, 1]
Out: {{0, 0}, 1, 1, 1, {0, 0, 0}, {{0, 0}, 0}, 1, 1}


The final '1' in the Replace[] expression indicates the level to act on. If you change it to '2' you instead get:

In: Replace[{{0, 0}, 0, 0, 0, {0, 0, 0}, {{0, 0}, 0}, 0, 0}, 0 -> 1, 2]
Out: {{1, 1}, 1, 1, 1, {1, 1, 1}, {{0, 0}, 1}, 1, 1}


EDIT

A word of caution on the solution using Replace[], this will only work if all elements with zeros that you want to replace only contain zeros. Say that you want to replace 'x' in the following:

In: Replace[{x, x + a, {x}}, x -> 1, 1]
Out: {1, a + x, {x}}


you see that the 'x' in the second element was not replaced. This is because it is at level 2, and not level 1. A possible solution to this is to use the Map[] as follows:

In: Map[If[ListQ[#], #, Replace[#, x -> 1, All]] &, {x, x + a, {x}}]
Out: {1, 1 + a, {x}}


note the 'All' at the level specification for Replace here. This means that 'x' on any level will be replaced, but only if the element is not a list.

Once again, there is probably a neater solution here to this more general case. Maybe someone else has a suggestion.

list = {{0, 0}, 0, 0, 0, {0, 0, 0}, {{0, 0}, 0}, 0, 0};


Using SequenceReplace (new in 11.3)

SequenceReplace[list, {0} :> 1]


{{0, 0}, 1, 1, 1, {0, 0, 0}, {{0, 0}, 0}, 1, 1}

Using ReplaceAt (new in 13.1)

ReplaceAt[list, _ :> 1, Position[list, 0, 1]]


{{0, 0}, 1, 1, 1, {0, 0, 0}, {{0, 0}, 0}, 1, 1}

list = {{0, 0}, 0, 0, 0, {0, 0, 0}, {{0, 0}, 0}, 0, 0};


Grabbing the @eldo's list and using SubsetMap:

SubsetMap[# + 1 &, list, Position[list, 0, 1]]

(*{{0, 0}, 1, 1, 1, {0, 0, 0}, {{0, 0}, 0}, 1, 1}*)