# merging certain list elements

I have a list of strings, some of which are all upper case, and some mixed upper and lower, and some are digits with commas:

lis = {"ABC","Abc","Def","1","DEF","Ghi","Jkl","MNO","1,"}


I would like to StringJoin adjacent elements that consist of mixed upper and lower cases to give:

res = {"ABC", "AbcDef","1","DEF","GhiJkl","MNO","1,"}


I can identify the elements of lis that contain lower case letters easily enough:

StringContainsQ[tes,CharacterRange["a","z"]


but I don't know how to make a rule to StringJoin adjacent elements that return True. Thanks for suggestions.

You can useSequenceReplace:

SequenceReplace[lis, {a__} /;
And @@ (StringContainsQ[{a}, Alternatives @@ CharacterRange["a", "z"]]) :>
StringJoin[a]]

% == res


True

Faster alternatives:

SequenceReplace[lis, {a__}/; Nor @@ StringFreeQ[_?LowerCaseQ] @ {a}:> StringJoin[a]]


and

StringJoin /@ Split[lis, Nor @@ StringFreeQ[_?LowerCaseQ] @ {##}&]

• Seems you beat me by a minute ;) – Lukas Lang Sep 16 '19 at 17:12
• Thank you both for the solutions! They work. Unfortunately my data set is large and both these approaches take some time to execute; any thoughts for further efficiency? – Suite401 Sep 16 '19 at 17:48
• @kglr - MUCH better - Thanks! – Suite401 Sep 16 '19 at 18:23

[Edit: Just noticed that @kglr was slightly faster in posting a very similar solution - I'll leave this here since it is at least slightly different, in that it merges arbitrarily many consecutive strings, while @kglr's solution only merges pairs]

You can use SequenceReplace:

SequenceReplace[
lis,
{strs__?(StringContainsQ@CharacterRange["a", "z"])} :>
StringJoin@strs
]
(* {"ABC", "AbcDef", "1", "DEF", "GhiJkl", "MNO", "1,"} *)

• Lukas, good point re pairs vs arbitrary consecutive pairs. (+1) – kglr Sep 16 '19 at 17:16
• i updated with a version that handles sequences of consecutive strings. – kglr Sep 16 '19 at 17:24

Less elegant but fast solution:

lis //
{#, StringContainsQ[#, CharacterRange["a", "z"]]} & //
Transpose //
SplitBy[#, Last] & //
Map[ If[ Last@First@#, StringJoin@(#[[All, 1]]), Sequence @@ (#[[All, 1]]) ] &]