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$
10
$\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}}
$\endgroup$
2
  • $\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 '20 at 22:07
  • $\begingroup$ You are a godsend. Thank you so much. $\endgroup$
    – KyCygni
    Jul 22 '20 at 16:20
4
$\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
$\endgroup$
2
  • 3
    $\begingroup$ Slightly simpler is: SequenceReplace[{1, 0, 1} -> Sequence[1, 1, 1]] /@ testlist $\endgroup$
    – Carl Woll
    Jul 21 '20 at 0:25
  • $\begingroup$ These are great! Really appreciate the help. $\endgroup$
    – KyCygni
    Jul 22 '20 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.