4
$\begingroup$

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.

$\endgroup$
5
$\begingroup$

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] @ {##}&]
$\endgroup$
  • $\begingroup$ Seems you beat me by a minute ;) $\endgroup$ – Lukas Lang Sep 16 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 at 17:48
  • $\begingroup$ @kglr - MUCH better - Thanks! $\endgroup$ – Suite401 Sep 16 at 18:23
4
$\begingroup$

[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,"} *)
$\endgroup$
  • $\begingroup$ Lukas, good point re pairs vs arbitrary consecutive pairs. (+1) $\endgroup$ – kglr Sep 16 at 17:16
  • 1
    $\begingroup$ i updated with a version that handles sequences of consecutive strings. $\endgroup$ – kglr Sep 16 at 17:24
2
$\begingroup$

Less elegant but fast solution:

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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