## DEV Community is a community of 890,060 amazing developers

We're a place where coders share, stay up-to-date and grow their careers. # Daily Challenge #270 - Fix String Case

In this challenge, you will be given a string that may have mixed uppercase and lowercase letters and your task is to convert that string to either lowercase only or uppercase only based on:

• making as few changes as possible
• if the string contains equal number of uppercase and lowercase letters, convert the string to lowercase.
``````For example:
solve("coDe") = "code". Lowercase characters > uppercase. Change only the "D" to lowercase.
solve("CODe") = "CODE". Uppercase characters > lowecase. Change only the "e" to uppercase.
solve("coDE") = "code". Upper == lowercase. Change all to lowercase.
``````

Tests:
solve("code")
solve("CODe")
solve("COde")
solve("Code")

Good luck!

This challenge comes from KenKamau on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

## Discussion (13) SavagePixie

JavaScript

Something like this should do it:

``````const solve = str => str.replace(/[a-z]/g, '').length > str.length / 2
? str.toUpperCase()
: str.toLowerCase()
`````` Reinhart Previano K. • Edited on

“A simple step for RegEx. A huge leap for a bunch of loops and `if`s.” agtoever • Edited on

Python solution. Uses helper function that counts the matching elements in a list. I use that to compare the string to itself converted to upper- and lowercase.

``````def matching(l1, l2):
# Returns the number of matching corresponding elements of l1 and l2
return sum(e1 == e2 for e1, e2 in zip(l1, l2))

def solve(s):
return s.lower() if matching(s, s.upper()) <= matching(s, s.lower()) else s.upper()

cases = ["coDe", "CODe", "coDE", "code", "CODe", "COde", "Code"]
for case in cases:
print(f'{case} -> {solve(case)}')
`````` in nim:

``````import strutils

proc solve*(s: string): string =
var lower = 0
var upper = 0
var lowerResult = ""
var upperResult = ""

for c in s:
if c.isLowerAscii():
inc(lower)
else:
inc(upper)

if lower >= upper:
return lowerResult

return upperResult

``````

probably too verbose but that way I am only looping once through the string :-) Michael Kohl • Edited on

I am only looping once through the string :-)

Though at the cost of building an entire output string (including potential case conversions), you're then discarding.

I'd probably go for a more straightforward approach:

``````import sequtils, strutils

func solve*(s: string): string =
if s.countIt(it.isUpperAscii) > s.len.div(2):
s.toUpperAscii
else:
s.toLowerAscii
`````` Michael Kohl

I don’t think efficiency matters much here, but my solution has a lower cyclomatic complexity and is potentially easier to understand for others. Ritheesh
``````def solve(inp):
lower_count = 0
length = len(inp)
for i in inp:
if i.islower():
lower_count += 1
if 2*lower_count >= length:
return inp.lower()
return inp.upper()
``````

Tests:
solve("code") = "code"
solve("CODe") = "CODE"
solve("COde") = "code"
solve("Code") = "code"

Please let me know if there are any changes to be made. peter279k

Here is the simple solution without any advanced approach (e.g. ASCII code converting, regular expression and so on.):

``````function solve(\$s) {
\$upperCases = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
\$lowerCases = strtolower(\$upperCases);

\$upperCaseCount = 0;
\$lowerCaseCount = 0;

\$index = 0;

for (; \$index<strlen(\$s); \$index++) {
if (strpos(\$upperCases, \$s[\$index]) !== false) {
\$upperCaseCount += 1;
}
if (strpos(\$lowerCases, \$s[\$index]) !== false) {
\$lowerCaseCount += 1;
}
}

if (\$upperCaseCount > \$lowerCaseCount) {
return strtoupper(\$s);
}

if (\$upperCaseCount <= \$lowerCaseCount) {
return strtolower(\$s);
}
}
`````` willsmart

Here's a C implementation that does a pretty good job at being as lazy as possible (which is what I always aspire to, even if it ends up being a lot of work to get to be lazy)

It updates the string in-place, passing through only once if nothing is to be done, or if its original guess of the final case was right. Otherwise, it passes through again only up to the last char it guessed wrong on.
Worst case, it iterates the string twice (minus one last character on the second pass), but the typical case is more like a single pass.

In C for old-times sake, and because if you're bothering to do this sort of thing at all it'd better be in a performant language just to make any of it worth the effort.

``````#include <stdio.h>
#include <string.h>

#define DEB(...) __VA_ARGS__

#define ascii_A 65
#define ascii_Z 90
#define isUpperCase(___c) (((___c) & ascii_case_bitmask) == 0)

void convertToPopularCase(char *s) {
int stat_toggleCount = 0, stat_stringLength = (int)strlen(s);
printf(">>> %s\n", s);

int lastWrongIndex = -1, upperCount = 0, lowerCount = 0;
char upperFTW = 0;
for (int i=0; s[i]; i++) {
const char c = s[i], upperC = c & ~ascii_case_bitmask, isUpper = isUpperCase(c);
if (upperC < ascii_A || upperC > ascii_Z) continue; // non-letters are ignored
upperCount += isUpper;
lowerCount += 1 - isUpper;
if (upperFTW != upperCount > lowerCount) {
lastWrongIndex = i - 1;
upperFTW = !upperFTW;
}
if (isUpper != upperFTW) {
toggleCase(s[i]); // toggle case of char in string
stat_toggleCount++;
}
}
for (int i=0; i <= lastWrongIndex; i++) {
const char c = s[i], upperC = c & ~ascii_case_bitmask, isUpper = isUpperCase(c);
if (upperC < ascii_A || upperC > ascii_Z) continue;
if (isUpper != upperFTW) {
toggleCase(s[i]); // toggle case of char in string
stat_toggleCount++;
}
}

printf(" << %s\n    (Length: %d, chars toggled: %d, total string passes including cleanup: %f\n\n", s, stat_stringLength, stat_toggleCount, (stat_stringLength + (lastWrongIndex + 1))/(float)stat_stringLength);
}

int main()
{
char testStrings[] = {
"Following examples should be uppercase>>>",
"CODE",
"CODe",
"cODE",
"A MoNkEy",
"123456789 CODE",
"four - FIVEE + four - FIVEE",
"four + fivee - FOUR - SIXXXX",

"Following examples should be lowercase>>>",
"code",
"COde", "Code",
"coDE", "codE",
"MoNkEy",
"123456789 code", "123456789 coDE",
"four + fivee - FOUR - FIVEE",
};

for (int i=0, N = sizeof(testStrings)/sizeof(*testStrings); i<N; i++) {
convertToPopularCase(testStrings[i]);
}

return 0;
}
``````

Output:
(a "total string passes including cleanup" of 1 is where the string was just passed over once)

``````>>> Following examples should be uppercase>>>
<< following examples should be uppercase>>>
(Length: 41, chars toggled: 1, total string passes including cleanup: 1.024390

>>> CODE
<< CODE
(Length: 4, chars toggled: 0, total string passes including cleanup: 1.000000

>>> CODe
<< CODE
(Length: 4, chars toggled: 1, total string passes including cleanup: 1.000000

>>> cODE
<< CODE
(Length: 4, chars toggled: 3, total string passes including cleanup: 1.500000

>>> A MoNkEy
<< A MONKEY
(Length: 8, chars toggled: 3, total string passes including cleanup: 1.000000

>>> 123456789 CODE
<< 123456789 CODE
(Length: 14, chars toggled: 0, total string passes including cleanup: 1.714286

>>> four - FIVEE + four - FIVEE
<< FOUR - FIVEE + FOUR - FIVEE
(Length: 27, chars toggled: 22, total string passes including cleanup: 1.925926

>>> four + fivee - FOUR - SIXXXX
<< FOUR + FIVEE - FOUR - SIXXXX
(Length: 28, chars toggled: 27, total string passes including cleanup: 1.964286

>>> Following examples should be lowercase>>>
<< following examples should be lowercase>>>
(Length: 41, chars toggled: 1, total string passes including cleanup: 1.024390

>>> code
<< code
(Length: 4, chars toggled: 0, total string passes including cleanup: 1.000000

>>> COde
<< code
(Length: 4, chars toggled: 4, total string passes including cleanup: 1.750000

>>> Code
<< code
(Length: 4, chars toggled: 1, total string passes including cleanup: 1.250000

>>> coDE
<< code
(Length: 4, chars toggled: 2, total string passes including cleanup: 1.000000

>>> codE
<< code
(Length: 4, chars toggled: 1, total string passes including cleanup: 1.000000

>>> MoNkEy
<< monkey
(Length: 6, chars toggled: 3, total string passes including cleanup: 1.833333

>>> 123456789 code
<< 123456789 code
(Length: 14, chars toggled: 0, total string passes including cleanup: 1.000000

>>> 123456789 coDE
<< 123456789 code
(Length: 14, chars toggled: 2, total string passes including cleanup: 1.000000

>>> four + fivee - FOUR - FIVEE
<< four + fivee - four - fivee
(Length: 27, chars toggled: 9, total string passes including cleanup: 1.000000
`````` Valts Liepiņš

``````import Data.List (foldl')
import Data.Char (toLower, toUpper, isLower)

solve :: String -> String
solve str =
if fromIntegral nLower / nTotal >= 0.5
then toLower <\$> str
else toUpper <\$> str
where
(nLower, nTotal) = foldl' counter (0,0) str
counter (nLower, nTotal) ch =
if isLower ch
then (nLower+1, nTotal+1)
else (nLower, nTotal+1)
`````` Zohar Peled

Is it really a challenge?

``````string solve(string input)
{
return input.Count(c => char.IsUpper(c)) > input.Length / 2
? input.ToUpper()
: input.ToLower();
}
`````` Pavitra Golchha

# Kotlin

``````fun solve(input: String): String
= if (input.count { it.isUpperCase() } > input.length / 2) input.toUpperCase() else input.toLowerCase()
``````