7
$\begingroup$

Given a list of Booleans:

exampleInput = {1, 1, 0, 1, 0, 0, 1, 0};

and given the string:

string = "\\xa , \\xb , \\xc , \\xd , \\xe , \\xf , \\xg , \\xh";

The challenge is to replace the lower case letters $\{a,b,c,d,e,f,g,h\}$ with capital letters $\{A,B,C,D,E,F,G,H\}$ at the positions where $1$'s occur in the list of Booleans.

exampleOutput = "\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

Challenge/Question:

come up with an elegant or surprising way to do this.


all code for convenience:

exampleInput = {1, 1, 0, 1, 0, 0, 1, 0};
string = "\\xa , \\xb , \\xc , \\xd , \\xe , \\xf , \\xg , \\xh";
$\endgroup$
6
$\begingroup$

Update: A few additional alternatives:

Make list of functions out of exampleInput:

foo = exampleInput /. {0 -> Identity, 1 -> ToUpperCase};

You can use foo with StringReplace or with StringReplacePart in several ways:

StringReplace[string, "x" ~~ a_ :> "x"<> Last[foo = RotateLeft[foo]][a]]

or (using @J.M.'s regular expression pattern):

StringReplace[string, 
  RegularExpression["(?![x])[a-z]"] :> Last[foo = RotateLeft[foo]]["$0"]]

or

Block[{i = 1}, StringReplace[string, "x" ~~ a_ :> "x"<> foo[[i++]][a]]]

or

pos = 1 + StringPosition[string, "x"];

StringReplacePart[string, Construct @@@ Thread[{foo, StringTake[string, pos]}], pos]

or

StringReplacePart[string, MapThread[Compose, {foo, StringTake[string, pos]}], pos]

Original answer:

StringRiffle[MapAt[StringReplace["x" ~~ a_ :> "x" <> ToUpperCase[a]], 
  StringSplit[string, ","], Position[exampleInput, 1]], ","]

"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

Alternatively,

spos = 1 + Pick[StringPosition[string, "x"], exampleInput, 1];

StringReplacePart[string, ToUpperCase[StringTake[string, spos]], spos]

"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

and

ClearAll[stringMapAt]
stringMapAt = StringJoin@MapAt[#, Characters@#2, #3] &;

stringMapAt[ToUpperCase, string, spos[[All, {1}]]]

"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

|improve this answer|||||
$\endgroup$
4
$\begingroup$

A variation of the first answer in kglr's post that doesn't deconstruct and reconstruct the list:

Module[{i = 1}, 
  StringReplace[
    string, "x" ~~ a_ :> "x" <> If[exampleInput[[i++]] == 1, ToUpperCase@a, a]
   ]
 ]

"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

Slightly more verbose but not requiring checking with the If statement:

Module[{i = 1}, 
  StringReplace[string, 
    "x" ~~ z_ :>  "x" <> FromCharacterCode[First@ToCharacterCode[z] - 32 exampleInput[[i++]]]
   ]
 ]
|improve this answer|||||
$\endgroup$
4
$\begingroup$

Here's how to use a regex with "negative lookahead" in conjunction with Pick[]:

With[{pos = Pick[StringPosition[string, RegularExpression["((?![x])[a-z])"]], 
                 exampleInput, 1]},
     StringReplacePart[string, ToUpperCase[StringTake[string, pos]], pos]]
   "\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"
|improve this answer|||||
$\endgroup$
3
$\begingroup$
exampleInput = {1, 1, 0, 1, 0, 0, 1, 0};
string = "\\xa , \\xb , \\xc , \\xd , \\xe , \\xf , \\xg , \\xh";

Since this question seems more along the lines of code golf (which I'm all in favor of), I won't put generality as much of a priority.

Replacement

With[
  {lets = Pick[Alphabet[][[;; Length@exampleInput]], exampleInput, 1](*{a,b,...,h}*)}, 
  StringReplace[string, char : Alternatives @@ lets :> ToUpperCase@char]
]
"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

Brute force

With[
  {lets = Pick[Alphabet[][[;; Length@exampleInput]], exampleInput, 1]}, 
  If[MemberQ[lets, #], ToUpperCase@#, #] & /@ Characters@string // StringJoin
]
"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

Pattern Exploitation

And if we want to use the symmetry/pattern that each a, b, etc are separated by 6 characters (starting at the third character of the string).

StringJoin@MapAt[
  ToUpperCase, 
  Characters@string,
  Thread@{Pick[Range[3, StringLength@string, 6], exampleInput, 1]}
]
"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

Pattern exploitation, indicator functions, and generalized inner products

First we notice that the indexing letters (a, ..., h), denoted by let, all have 5 characters between them.

Then we pad the indicator function exampleInput (in the sense of which letters, out of all the letters, are to be capitalized) to be the same length as the string

indic = (exampleInput /. x : (0 | 1) :> {0, 0, 0, 0, 0, x} // Flatten)[[4 ;;]]

stripping off unnecessary leading zeros. This gives a list of ones where the letters-to-be-capitalized are, and zeros elsewhere.

Then, being inspired from @kglr's foo

funcs = indic /. {0 -> Identity, 1 -> ToUpperCase}

Then we take the generalized inner product between funcs and the character list

Inner[#1@#2 & (*or Construct in version >= 11.3*), funcs, Characters@string, StringJoin]
"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

Or all together

With[
  {indic = (exampleInput /. x : (0 | 1) :> {0, 0, 0, 0, 0, x} // Flatten)[[4 ;;]]},
  Inner[#1@#2 &, indic /. {0 -> Identity, 1 -> ToUpperCase}, Characters@string, StringJoin]
]
|improve this answer|||||
$\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.