5
$\begingroup$

Suppose I have a list of multiple sublists:

testlist={{1,1,1,0,0,0,1,1,1,0,1,1},{1,0,0,1,1,1,1,0,1,1,1,0}}

I want to replace given sequences without creating new sublists and without flattening.

For example, I'd like to replace all instances of {1,0,1} within all sublists with {1,1,1}. The final output for the above should be:

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

Here are some attempts to show the issue:

testlist = {{1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1}, {1, 0, 0, 1, 1, 1, 
   1, 0, 1, 1, 1, 0}}
Replace[testlist, {1, 0, 1} :> {1, 1, 
   1}, {2}]; (* This does nothing; Replace doesn't accept sequences *)
\

Replace[testlist, 
 1 :> {2, 2}, {2}] (* Even if it did work, Replace creats new \
sublists *)
(* Output: \
{{{2,2},{2,2},{2,2},0,0,0,{2,2},{2,2},{2,2},0,{2,2},{2,2}},{{2,2},0,0,\
{2,2},{2,2},{2,2},{2,2},0,{2,2},{2,2},{2,2},0}} *)

ReplaceAll[{1, 0, 1} -> {1, 1, 1}][testlist];
testlist /. {{1, 0, 1} -> {1, 1, 
    1}}; (* These two both do nothing: same reason *)
testlist //. 0 -> 2 (* This works as you'd expect *)
(* Output: {{1,1,1,2,2,2,1,1,1,2,1,1},{1,2,2,1,1,1,1,2,1,1,1,2}} *)
testlist //. {Sequence[1, 0, 1] -> 
   Sequence[1, 1, 1]}; (* This does nothing *)

f1[x_List] := 2*x
f1@testlist[[All]] (*This works as you'd expect*)
(* Output: {{2,2,2,0,0,0,2,2,2,0,2,2},{2,0,0,2,2,2,2,0,2,2,2,0}} *)
f2[x_List] := SequenceReplace[x, {1, 0, 1} -> Sequence[1, 1, 1]]
f2@testlist[[All]]; (*This does nothing*)
f2 @@@ testlist (* This doesn't work *)
(* Output: {f2[1,1,1,0,0,0,1,1,1,0,1,1],f2[1,0,0,1,1,1,1,0,1,1,1,0]} *)
\

SequenceReplace[
 Flatten@testlist, {1, 0, 1} -> 
  Sequence[1, 1, 1]] (* This works provided there are no sublists *)
(* Output: {1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0} *)

testlist /. {1 -> 
   Sequence @@ {2, 
     2}}(* This works and makes a replacement within the desired \
sublists *)
(* Output: \
{{2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,0,2,2,2,2},{2,2,0,0,2,2,2,2,2,2,2,2,0,\
2,2,2,2,2,2,0}} *)
testlist /. {Sequence[1, 0, 1] -> 
   Sequence @@ {1, 1, 1}} (* This does nothing *)

This feels like it should be simple, but all the documentation I can find only provides solutions for single lists, not sublists, and everything I find that says "You can do this for any level you want" doesn't work for sequences.

I can force the answer with a For loop, but I'd like to extend this code to lists with thousands of numbers, and then run it for multiple lists, which doesn't have acceptable scaling.

$\endgroup$
9
$\begingroup$

You can use pattern matching with BlankNullSequence

testlist //. {List[a___,1,0,1,b___] :> List[a,1,1,1,b]}
{{1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0}}
| improve this answer | |
$\endgroup$
  • $\begingroup$ By far the most elegant and really good use for BlankNullSequence! I found about it just last week and i was wondering how it can be used. Thanks! $\endgroup$ – Alex Jul 21 at 22:07
  • $\begingroup$ You are a godsend. Thank you so much. $\endgroup$ – KyCygni Jul 22 at 16:20
3
$\begingroup$

Another way

SequenceReplace[{1, 0, 1} -> {1, 1, 1}] /* Flatten /@ testlist

Inspired by @carl woll's comment

SequenceReplace[{1, 0, 1} -> Splice[{1, 1, 1}]] /@ testlist
| improve this answer | |
$\endgroup$
  • 3
    $\begingroup$ Slightly simpler is: SequenceReplace[{1, 0, 1} -> Sequence[1, 1, 1]] /@ testlist $\endgroup$ – Carl Woll Jul 21 at 0:25
  • $\begingroup$ These are great! Really appreciate the help. $\endgroup$ – KyCygni Jul 22 at 16:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.