6
$\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$

4 Answers 4

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
    Commented Jul 21, 2020 at 22:07
  • $\begingroup$ You are a godsend. Thank you so much. $\endgroup$
    – KyCygni
    Commented Jul 22, 2020 at 16:20
5
$\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
    Commented Jul 21, 2020 at 0:25
  • $\begingroup$ These are great! Really appreciate the help. $\endgroup$
    – KyCygni
    Commented Jul 22, 2020 at 16:21
1
$\begingroup$
list = 
 {{1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1}, {1, 0, 0, 1, 1, 1, 1, 0,1, 1, 1, 0}};

Using SequenceCases with Splice (new in 12.1)

SequenceCases[#, {a___, 1, 0, 1, b___} :> Splice[{a, 1, 1, 1, b}]] & /@ list

{{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$
1
  • 1
    $\begingroup$ (+1) Shorter: SequenceCases[list, {{a___, 1, 0, 1, b___}} :> {a, 1, 1, 1, b}] $\endgroup$ Commented Feb 22 at 1:52
1
$\begingroup$
list = {{1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1}, {1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0}};

Using ReplaceList:

ReplaceList[list, {___, {a___, 1, 0, 1, b___}, ___} :> {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$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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