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:


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


3 Answers 3


You can useSequenceReplace:

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

% == res


Faster alternatives:

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


StringJoin /@ Split[lis, Nor @@ StringFreeQ[_?LowerCaseQ] @ {##}&]
  • $\begingroup$ Seems you beat me by a minute ;) $\endgroup$
    – Lukas Lang
    Sep 16, 2019 at 17:12
  • $\begingroup$ 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? $\endgroup$
    – Suite401
    Sep 16, 2019 at 17:48
  • $\begingroup$ @kglr - MUCH better - Thanks! $\endgroup$
    – Suite401
    Sep 16, 2019 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:

  {strs__?(StringContainsQ@CharacterRange["a", "z"])} :> 
(* {"ABC", "AbcDef", "1", "DEF", "GhiJkl", "MNO", "1,"} *)
  • $\begingroup$ Lukas, good point re pairs vs arbitrary consecutive pairs. (+1) $\endgroup$
    – kglr
    Sep 16, 2019 at 17:16
  • 1
    $\begingroup$ i updated with a version that handles sequences of consecutive strings. $\endgroup$
    – kglr
    Sep 16, 2019 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]]) ] &]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.