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} *)
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}
SequenceReplace
would automatically skip the integers like this.
$\endgroup$
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}*)