Element combinations

I have a list:

lis = {"ab", "cde", 2,"rs",3,"tu","v","w",7}


and would like to get the following list:

lis2 = {abcde, 2,rs, 3,tuvw,7}


... with adjacent strings joined and separated by integers.

Any thoughts would be appreciated!

If you don't mind code that generates messages, then the following will work:

Quiet[List@@StringJoin[lis],StringJoin::string]

(* {abcde,2,rs,3,tuvw,7} *)

• Excellent! Thanks Commented Jan 28, 2017 at 4:06
List @@ StringExpression @@ lis


{"abcde", 2, "rs", 3, "tuvw", 7}

In version 10 and later versions you can also use SequenceCases with an appropriate pattern:

SequenceCases[lis, {a : Except[_String] ..., b__String, c : Except[_String] ...} :>
Sequence[a, StringJoin@b, c]]


{"abcde", 2, "rs", 3, "tuvw", 7}

lis = {"ab", "cde", 2, "rs", 3, "tu", "v", "w", 7};

lis //. {s___, str1_String, str2_String, f___} :>
{s, StringJoin[str1, str2], f}

(*  {"abcde", 2, "rs", 3, "tuvw", 7}  *)


or

lis //. {s___, str1_String, str2_String, f___} :>
{s, str1 <> str2, f}


This is a bit elaborate:

If[VectorQ[#, StringQ], StringJoin[#], Sequence @@ #] & /@ SplitBy[lis, StringQ]
{"abcde", 2, "rs", 3, "tuvw", 7}

SplitBy[lis,NumericQ] /. {{x__String} :> StringJoin[x], {x_?NumericQ} :> x}

list = {"ab", "cde", 2, "rs", 3, "tu", "v", "w", 7};


Using SequenceSplit (new in 11.3)

SequenceSplit[list, a : {_Integer} :> a[[1]]] /. {a__String} :> StringJoin[a]


{"abcde", 2, "rs", 3, "tuvw", 7}

Using SequenceReplace:

list = {"ab", "cde", 2, "rs", 3, "tu", "v", "w", 7};

SequenceReplace[list, {s__String} :> StringJoin[s]]


Result:

{"abcde", 2, "rs", 3, "tuvw", 7}

• +1, extremely nice. I didn't know that SequenceReplace would automatically skip the integers like this.
– eldo
Commented Jan 10 at 19:25

If we build ConsecutiveQ we can handle the problem as follows:

ConsecutiveQ[list_List] := AllTrue[Differences[list], # == 1 &]

p1 = Flatten[Position[list, _String]];
p2 = Complement[Range[Length@list], p1];
pstr = Transpose /@ List /@ SequenceCases[p1, {__}?ConsecutiveQ];
pnum = Transpose /@ List /@ SequenceCases[p2, {__}?ConsecutiveQ];
strs = Extract[list, #] & /@ pstr;
nums = Extract[list, #] & /@ pnum;

Flatten[Riffle[strs, nums] /. s_ /; MatchQ[s, {__?StringQ}] :> StringJoin@s]

(*{"abcde", 2, "rs", 3, "tuvw", 7}*)


Or using Cases and SplitBy:

SplitBy[list, StringQ]

Cases[%, s_ :> If[MatchQ[s, {__?StringQ}], StringJoin@s, Splice@s]]

(*{"abcde", 2, "rs", 3, "tuvw", 7}*)