4
$\begingroup$

I'm new to Mathematica, but with extensive searching and a lot of experimenting I can't seem to get this to work.

I have a list of strings of the form:

list = { "*A", "B", "*C", "D" , "E", "F", "*G", "H", "*I"};

The elements starting with * can be followed by zero or more elements that don't start with *. I am trying to use pattern matching to construct a function that would for example take f["*C"] and return { "D", "E", "F" }.

I've been trying:

Replace[list, { ___, "*C", 
   r : Repeated[ y_ /; ! hasStarQ[y]], ___} -> { "*C", r} ]

Where hasStarQ checks if the string starts with *. This almost produces the right result:

{"*C", "D"}

But I can't get it to match "D", "E", "F". Similar results for:

SequenceCases[list, {"*C", Longest[Repeated[ y_ /; ! hasStarQ[y]]]} ]

and

SequenceReplace[list, {___, "*C", 
   r : Longest[Repeated[ y_ /; ! hasStarQ[y]]], Shortest@___} :> r]

I recognise that I can achieve what I need using SplitBy but I wonder whether there is a more elegant way to achieve this goal!

$\endgroup$
1
  • $\begingroup$ SequenceCases[list, {"*C", x__?(NoneTrue[{##}, StringStartsQ["*"]] &)} :> {x}]? $\endgroup$
    – kglr
    Commented Jan 27 at 6:15

3 Answers 3

4
$\begingroup$
SequenceCases[list, 
    {"*C", x__} /;  Nor @@ StringStartsQ[{x}, "*"] :> {x}]
{{"D", "E", "F"}}
Cases[{"*C", x___} :> {x}]@Split[list, Not@StringStartsQ["*"]@#2 &]
{{"D", "E", "F"}}
$\endgroup$
1
  • 1
    $\begingroup$ Many thanks. So the trick is to test the whole results list rather than the individual elements. $\endgroup$
    – p quint
    Commented Jan 27 at 8:46
4
$\begingroup$
list = {"*A", "B", "*C", "D", "E", "F", "*G", "H", "*I"};

Build and query an Association

look =
 GroupBy[#, First -> Rest, First]& @ Split[list, !StringStartsQ[#2, "*"] &]

<|"*A" -> {"B"}, "*C" -> {"D", "E", "F"}, "*G" -> {"H"}, "*I" -> {}|>

look["*C"]

{"D", "E", "F"}

Lookup[look, {"*A", "*C", "*X"}, {}]

{{"B"}, {"D", "E", "F"}, {}}

$\endgroup$
1
$\begingroup$
list = {"*A", "B", "*C", "D", "E", "F", "*G", "H", "*I"};

Using SequenceSplit:

rep = {__, "*C", x__} /; Nor @@ StringStartsQ[{x}, "*"] :> {x};

Select[SequenceSplit[list, rep], ContainsOnly[StringFreeQ[#, "*"], {True}] &]

(*{{"D", "E", "F"}}*)

Or using SequenceReplace:

Cases[{__}]@SequenceReplace[list, rep]

(*{{"D", "E", "F"}}*)
$\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.