7
$\begingroup$

I have a string list consisting of alternating sequences of letters and digit characters. I would like to join the letter sequences and convert the digit characters into numbers composing a sublist of integers:

lis = {"a","bc","0","14","2","d","e","f","3","wx","z","r","st"}

I would like to obtain:

res = {{"abc"},{0,14,2},{"def"},{3},{"wxzrst"}}

Moving back and forth from symbols, numbers and string representation of digits makes for many lines of what must be extraneous code. I would be grateful for (and curious to see) ideas for economic code for this.

$\endgroup$

7 Answers 7

8
$\begingroup$
If[StringMatchQ[#[[1]], NumberString], FromDigits /@ #, {StringJoin@#}] & /@ 
 SplitBy[lis, StringMatchQ[NumberString]]

{{"abc"}, {0, 14, 2}, {"def"}, {3}, {"wxzrst"}}

or

SplitBy[If[StringMatchQ[#, NumberString], FromDigits@#, #] & /@ lis, Head] /.
 {s__String} :> {StringJoin@s}

{{"abc"}, {0, 14, 2}, {"def"}, {3}, {"wxzrst"}}

or

SequenceReplace[lis, 
  {{s__String?(Not@*StringMatchQ[NumberString] )} :> {StringJoin[s]} , 
  {n__String?(StringMatchQ[NumberString])} :> FromDigits /@ {n} } ]

   {{"abc"}, {0, 14, 2}, {"def"}, {3}, {"wxzrst"}}

$\endgroup$
6
$\begingroup$

Here's another variation similar to @kglr's:

SplitBy[
    List @@ StringExpression @@ StringReplace[lis, n:NumberString :> FromDigits[n]],
    Head
]

{{"abc"}, {0, 14, 2}, {"def"}, {3}, {"wxzrst"}}

$\endgroup$
4
$\begingroup$
Clear["Global`*"];
lis = {"a", "bc", "0", "14", "2", "d", "e", "f", "3", "wx", "z", "r", 
   "st"};
t1 = SplitBy[lis, StringMatchQ[NumberString]];

{{"a", "bc"}, {"0", "14", "2"}, {"d", "e", "f"}, {"3"}, {"wx", "z",
"r", "st"}}

Every other list has entries that will convert to numbers. To avoid verbosity later, define the following patterns:

listOfNumbers = {s__?(StringMatchQ[NumberString])};
listOfStrings = {s__String};

The idea is to MapAt the appropriate function at the correct sublist location. ToExpression gets applied to sublists that match the NumberString pattern. The resulting list has string only sublists that are catenated.

(MapAt[ToExpression, t1
   , Position[t1, listOfNumbers]]) // 
 MapAt[List@*Apply[StringJoin], #
   , Position[#, listOfStrings]] & 

{{"abc"}, {0, 14, 2}, {"def"}, {3}, {"wxzrst"}}

Advantage

The advantage is that now such a conversion can be applied to a selected number of desired locations. e.g., first two positions only or every other position by filtering the output from Position.

$\endgroup$
4
$\begingroup$

Using SequenceCases:

Riffle[
    Map[List @* StringJoin, SequenceCases[lis, {__ ? LetterQ}]],
    Map[ToExpression @* Most,
        SequenceCases[lis, {__ ? DigitQ, _ ? LetterQ}]
    ]
 ]

(*{{"abc"}, {0, 14, 2}, {"def"}, {3}, {"wxzrst"}}*)
$\endgroup$
3
$\begingroup$
num = StringMatchQ[#, NumberString] &;   

fun[{x_?num}] := ToExpression[x]
fun[x_] := StringJoin[x]

SplitBy[fun /@ Split[lis, !num[#1] && !num[#2] &], Head]

{{"abc"}, {0, 14, 2}, {"def"}, {3}, {"wxzrst"}}

$\endgroup$
2
$\begingroup$
list = {"a", "bc", "0", "14", "2", "d", "e", "f", "3", "wx", "z", "r", "st"};

Using SplitByPatterns by Ian Ford (Wolfram Research)

SplitByPatterns = ResourceFunction["SplitByPatterns"];

SplitByPatterns[list, {_?DigitQ}] /.
 {x : {__String?DigitQ} :> ToExpression[x],
  x : {__String} :> {StringJoin[x]}}

{{"abc"}, {0, 14, 2}, {"def"}, {3}, {"wxzrst"}}

$\endgroup$
2
$\begingroup$

Just to participate:

Using:

lis = {"a", "bc", "0", "14", "2", "d", "e", "f", "3", "wx", "z", "r", 

"st"};

then

ptn = Length /@ Split[LetterQ /@ lis];
If[And @@ LetterQ /@ #, StringJoin @@ #, FromDigits /@ #] & /@FoldPairList[TakeDrop, lis, ptn]

-> {"abc", {0, 14, 2}, "def", {3}, "wxzrst"}

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