Daily Challenge #210 - Separate Capitalization

thepracticaldev profile image dev.to staff ・1 min read

Given a string, capitalize the letters that occupy even indexes and odd indexes separately, and return as shown below. Index 0 will be considered even.

For example, capitalize("abcdef") = ['AbCdEf', 'aBcDeF']. The input will be a lowercase string with no spaces.



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!

Posted on by:

thepracticaldev profile

dev.to staff


The hardworking team behind dev.to ❀️


Editor guide

Python 3.8+ solution (bc type hints) using nested function and enumeration.

from typing import List, Literal

def capitalize(text: str) -> List[str]:
    def _change_case(text: str, posi: Literal["even", "odd"]):
        # Default to even index
        remainder = {"odd": 1}.get(posi, 0)
        return  "".join(
            v.upper() if i % 2 == remainder else v
            for i, v in enumerate(text)

    return [_change_case(text, "even"), _change_case(text, "odd")]

Alternate Python 3.6+ (ish?) version that uses a lambda function and functools.partial. This was my initial idea and I finally got it. πŸ˜…

from functools import partial
from typing import Tuple

def capitalize(text: str) -> Tuple[str, str]:
    # Create a lambda function that performs the casing
    _changer = lambda text, change_even: "".join(
        v.upper() if i % 2 != int(change_even) else v
        for i, v in enumerate(text)

    # Produce a partial function that prefills the given text
    _change_even_casing = partial(_changer, text)

    # Using our partial function, alter the strings
    return (_change_even_casing(True), _change_even_casing(False))

If you return like this return _change_even_casing(True), _change_even_casing(False) python will understand that it's already a tuple

Oh, I know. I put the parenthesis because it helps me better understand what is happening. πŸ˜‰πŸ˜‰



[local] dian#dian= WITH seq AS (
  SELECT regexp_split_to_table('string', '') AS c
), capitalized AS (
      WHEN row_number() OVER () % 2 = 0 THEN upper(c)
      ELSE lower(c)
    END AS even,
      WHEN row_number() OVER () % 2 = 1 THEN upper(c)
      ELSE lower(c)
    END AS odd
  FROM seq
  string_agg(even, '') AS even,
  string_agg(odd, '') AS odd
FROM capitalized;
  even  β”‚  odd   
 sTrInG β”‚ StRiNg
(1 row)

Time: 0.613 ms

Break the string down into a table with one character per row, use the row_number window function to capitalize it each way, then reassemble the final product; the latter two steps can't be combined because window functions can't be nested in aggregate functions.


The split to rows + window function approach is πŸ₯°



A good old fold and I use the Next type to know which side to capitalize next.

sealed trait Next
case object Left extends Next
case object Right extends Next

def capitalize (str: String): (String, String) = {
  val (l, r, _) = str.foldLeft(("", "", Left: Next)) {
    case ((l, r, n), c) => n match {
      case Left  => (l :+ c.toUpper, r :+ c.toLower, Right)
      case Right => (l :+ c.toLower, r :+ c.toUpper, Left)
  (l, r)

println(capitalize("abcdef")) // ("AbCdEf", "aBcDeF")
function capitalize(str) {
  return str.split("").reduce((acc, cur, i) => {
      odd = i % 2,
      upper = cur.toUpperCase();
    acc[0] += !odd ? upper : cur;
    acc[1] += odd ? upper : cur;
    return acc;
  }, ["", ""]);

Interesting JS solution....I haven't seen ternary operators used so haphazardly before, I'm not comfortable with them still.



Note: returning a tuple because returning a List String would mean it can be a list of 0 element as it can be a list of 10, 100, 1000, Infinity elements. Returning a Tuple gives the information to the user that this function will always return two elements in this case, which is suggested by the goal of this challenge. It will be then possible to extract them easily with the Tuple.first & Tuple.second functions.

even : Int -> Bool
even integer =
    modBy 2 integer == 0

odd : Int -> Bool
odd integer =
    not <| even integer

upperIf : ( Int -> Bool ) -> Int -> Char -> Char
upperIf predicate index character =
    if predicate index then
        Char.toUpper character


capitalizeIf : ( Int -> Bool ) -> String -> String
capitalizeIf predicate string =
        |> String.toList
        |> List.indexedMap ( upperIf predicate )
        |> String.fromList

capitalize : String -> ( String, String )
capitalize string =
    ( capitalizeIf even string, capitalizeIf odd string ) 

This is a hallmark of proper functional programming. Elm looks intimidating than more traditional grammars but it's essentially strongly-typed function composition. I love it, and the outer function reads like english.


I won't lie, since this was my first real functional programming language, it was tough, really tough. And this is essentially due to the fact that I was not used to no parens (or not at the same position at least) and function composition mainly.

But functional programming is like a muscle. The best competitors are working hard to obtain a great physical condition. This is the same thing for people like you and me that are used to procedural or oriented-object programming. It requires a lot of practices to get out of our habits.

But when you practiced enough, you'll start to love functional programming and that is the only certainty you have. The rest is up to you. And actually, since I'm a Web Developer, and doing most of my stuff in JavaScript at work (I hope I get to include Elm one day) this has made me a better overall JavaScript developer. There is no time wasted on learning this language, trust me.


Kinda silly solution using 2 mutually recursive functions (Haskell)

import Data.Char (toUpper, toLower) 

skip :: String -> String
skip [] = [] 
skip (c:cs) = c : capitalize' cs

capitalize' :: String -> String
capitalize' [] = [] 
capitalize' (c:cs) = toUpper c : skip cs

capitalize :: String -> (String, String) 
capitalize cs = (capitalize' cs, skip cs) 

Ooh, clever! I like it!


I'm a bit late to the party, but here's my Elixir solution:

defmodule Letters do
  import Integer, only: [ is_even: 1, is_odd: 1 ]

  def capitalise(str) do
      |> String.split("", trim: true)
      |> Enum.with_index
      |> Enum.map(&_mapper/1)
      |> Enum.unzip
      |> _join

  defp _mapper({ letter, idx })
    when is_even(idx) do
      { String.capitalize(letter), String.downcase(letter) }
  defp _mapper({ letter, idx })
    when is_odd(idx) do
      { String.downcase(letter), String.capitalize(letter) }
  defp _join({ a, b }), do: { Enum.join(a), Enum.join(b) }

Here's a fun little OCaml version:

open Base

let capitalize s =
  String.to_list s
  |> List.mapi ~f:(fun i c ->
         if i % 2 = 0
         then Char.(uppercase c, lowercase c)
         else Char.(lowercase c, uppercase c))
  |> List.unzip
  |> fun (a, b) -> String.of_char_list a, String.of_char_list b

ARR=$(seq 0 $(( ${#1} - 1 )))
LOWER=$(echo "$1" | tr '[:upper:]' '[:lower:]')

for x in $ARR; do 
  (( $x % 2 == 0 )) && ARR_EVEN+=$(echo "${LOWER:$x:1}" | tr '[:lower:]' '[:upper:]') || ARR_EVEN+=$(echo "${LOWER:$x:1}")
  (( $x % 2 )) && ARR_ODD+=$(echo "${LOWER:$x:1}" | tr '[:lower:]' '[:upper:]') || ARR_ODD+=$(echo "${LOWER:$x:1}")

echo ${ARR_EVEN[@]} ${ARR_ODD[@]}

Here is some shit I wrote using shellscript


One more Python solution:

def capitalize(s: str) -> list:
    cap_s_even, cap_s_odd = "", ""
    for i in range(0, len(s)):
        if i % 2 == 0:
    return [cap_s_even, cap_s_odd]

Solution in Haskell using folding:

import Data.Char (toUpper)

capitalize :: String -> [String]
capitalize str = folder skipCase <$> [("",0),("",1)] <*> pure str
    folder fn init = fst . foldr fn init
    skipCase :: Char -> (String, Int) -> (String, Int)
    skipCase c (cs, i) | i `mod` 2 == 1 = ((toUpper c):cs, i+1)
                       | otherwise      = (c:cs, i+1)

The skipCase folding function takes care of upcasing every 2. letter. The folder is a makes it easier to map the function over both capitalization variations, which then can be applied to the input string.



method = ->(s) { s.each_char.with_index.map { |c,i| [c.downcase,c.upcase].rotate(i[0])}.transpose.map(&:join)}

method.call 'dev'
=> ["dEv", "DeV"]

method.call 'method'
=> ["mEtHoD", "MeThOd"]

method.call 'hello'
=> ["hElLo", "HeLlO"]

Any Python version 2.7+.

>>> MiXeD = lambda s: ''.join(x.upper() if i&1==m else x for m in (0,1) for i, x in enumerate(s+' ')).split()
>>> MiXeD('abcdef')
['AbCdEf', 'aBcDeF']

😳 😱


This is the magic of python. Short. I just love it. πŸ’—


var capitalize = (word) => {
const split = word.split('');
const firstWord = split.map( (a, i) => i%2 === 0 ? a.toUpperCase() : a)
const secondWord = split.map( (a, i) => i%2 !== 0 ? a.toUpperCase() : a)
return [firstWord.join(''), secondWord.join('')];