5
$\begingroup$

I have a list from which I need to select up to two elements that follow each occurrence of a marker.

For example, the selected marker is {"b","c"} and the list is as follows:

  lis = {"a",{"b","c"},{"d","e"},{"f","g"},"h","i",{"b","c"},{"j","k"},{"l","m"},{"o"}}

This should give:

  res = {{{"d","e"},{"f","g"}},{{"j","k"},{"l","m"}}}

Thanks for any suggestions.

$\endgroup$
1
  • $\begingroup$ "Thank you Bill, lericr and Syed for the help! I will time some of these." I am honestly curious and I really do want to understand. What is it that makes people want the most efficient and the fastest possible and need to time this and ... people often make comments like that here, when they are using an interpreted rule based programming language that isn't really intended for speed? Is it because there isn't really anything else so might as well want the fastest possible speed? I'm not being rude, really, I just don't understand and would like to understand. Why is this? Thanks $\endgroup$
    – Bill
    Aug 29 at 5:23

6 Answers 6

8
$\begingroup$
SequenceCases[lis, {{"b", "c"}, a_, b_} :> {a, b}]

That assumes that you don't want a match if fewer than two items follow the {"b","c"}.

If that assumption is invalid, then maybe something like

SequenceCases[lis, {{"b", "c"}, follow__} :> Take[{follow}, UpTo[2]], Overlaps -> True]

Or even

SequenceCases[lis, {{"b", "c"}, follow___} :> Take[{follow}, UpTo[2]], Overlaps -> True]
$\endgroup$
6
$\begingroup$

One way of doing that

Map[Take[lis,{#+1,#+2}]&,Flatten[Position[lis,{"b","c"}]]]

which returns

{{{d,e},{f,g}},{{j,k},{l,m}}}

and if you look at the InputForm of that you see it does include the quotes.

Please test that carefully on all the various kinds of input that you want to give it to make certain that you find any mistakes.

$\endgroup$
4
$\begingroup$
ClearAll[replaceMarkerWithNextKNeighborsInList]

replaceMarkerWithNextKNeighborsInList[list_, marker_, k_ : 2] := 
 Map[p |-> list[[p + 1 ;; UpTo[p + k]]]]@PositionIndex[list]@marker

Examples:

lis = {"a",{"b","c"},{"d","e"},{"f","g"},"h","i",{"b","c"}, 
       {"j","k"},{"l","m"},{"o"}};

replaceMarkerWithNextKNeighborsInList[lis, {"b", "c"}]
{{{"d", "e"}, {"f", "g"}}, {{"j", "k"}, {"l", "m"}}}
replaceMarkerWithNextKNeighborsInList[lis, {"b", "c"}, 4]
{{{"d", "e"}, {"f", "g"}, "h", "i"}, {{"j", "k"}, {"l", "m"}, {"o"}}}
$\endgroup$
2
$\begingroup$

With a slightly modified lis that may contain fewer items to pick after each of the markers:

lis = {"a", {"b", "c"}, {"d", "e"}, {"f", "g"}, "h", 
  "i", {"b", "c"}, {"j", "k"}, {"b", "c"}, {"l", "m"}, {"o"}}

Using Split, Take:

Split[lis, #2 != {"b", "c"} &] //
  Select[First@# == {"b", "c"} &] //
 Map[Take[#, {2, UpTo[3]}] & ]

{{{"d", "e"}, {"f", "g"}}, {{"j", "k"}}, {{"l", "m"}, {"o"}}}
$\endgroup$
1
  • $\begingroup$ Thank you Bill, lericr and Syed for the help! I will time some of these. $\endgroup$
    – Suite401
    Aug 29 at 3:53
2
$\begingroup$
ClearAll[kRightNeigbors]

kRightNeigbors[l_, k_ : 2] :=
   Map[p |-> l[[p + 1 ;; UpTo[p + k]]]] @* PositionIndex[l]

Examples:

kRightNeigbors[lis] @ {"b", "c"}
{{{"d", "e"}, {"f", "g"}}, {{"j", "k"}, {"l", "m"}}}
Quiet @ Check[kRightNeigbors[lis] @ {"b", "d"}, {}]
{}
kRightNeigbors[lis, 4] @ {"b", "c"}
{{{"d", "e"}, {"f", "g"}, "h", "i"}, {{"j", "k"}, {"l", "m"}, {"o"}}}
$\endgroup$
2
$\begingroup$

An alternative method using Extract and Cases:

Extract[#, Transpose@MapThread[Span @@@ {{#1 + 1, #2 - 1}, {#2 + 1, All}} &, 
Position[#, {"b", "c"}]]] &@Cases[lis, x_ /; Length[x] == 2]

(*{{{"d", "e"}, {"f", "g"}}, {{"j", "k"}, {"l", "m"}}}*)

Or using SubsetCases:

SubsetCases[lis, {{"b", "c"}, a_List, b_List} :> {a, b}]

(*{{{"d", "e"}, {"f", "g"}}, {{"j", "k"}, {"l", "m"}}}*)

Or using Cases:

Partition[Cases[#, x_ /; Length[x] == 2 && x =!= {"b", "c"}], Count[#, {"b", "c"}]] &@lis

(*{{{"d", "e"}, {"f", "g"}}, {{"j", "k"}, {"l", "m"}}}*)
$\endgroup$
6
  • 1
    $\begingroup$ The first one with Extract gives off a position error on my setup. Could you please verify? $\endgroup$
    – Syed
    Aug 30 at 5:00
  • $\begingroup$ Hi @Syed! In my configuration it does not generate any position error, and I just verified it. $\endgroup$ Aug 30 at 5:43
  • 1
    $\begingroup$ i.stack.imgur.com/3iqS4.png $\endgroup$
    – Syed
    Aug 30 at 6:04
  • $\begingroup$ i.stack.imgur.com/VjG5f.jpg $\endgroup$ Aug 30 at 6:10
  • 1
    $\begingroup$ I will try to figure it out. Thanks. $\endgroup$
    – Syed
    Aug 30 at 6:15

Your Answer

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

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