loading...

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.

Tests

capitalize("dev")
capitalize("method")
capitalize("hello")

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

pic
Editor guide
Collapse
cely717 profile image
Caleb

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")]
Collapse
cely717 profile image
Caleb

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))
Collapse
rafaacioly profile image
Rafael Acioly

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

Thread Thread
cely717 profile image
Caleb

Oh, I know. I put the parenthesis because it helps me better understand what is happening. 😉😉

Collapse
dmfay profile image
Dian Fay

SQL:

[local] dian#dian= WITH seq AS (
  SELECT regexp_split_to_table('string', '') AS c
), capitalized AS (
  SELECT
    CASE
      WHEN row_number() OVER () % 2 = 0 THEN upper(c)
      ELSE lower(c)
    END AS even,
    CASE
      WHEN row_number() OVER () % 2 = 1 THEN upper(c)
      ELSE lower(c)
    END AS odd
  FROM seq
)
SELECT
  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.

Collapse
citizen428 profile image
Michael Kohl

The split to rows + window function approach is 🥰

Collapse
avalander profile image
Avalander

Scala

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")
Collapse
fluffynuts profile image
Davyd McColl
function capitalize(str) {
  return str.split("").reduce((acc, cur, i) => {
    const 
      odd = i % 2,
      upper = cur.toUpperCase();
    acc[0] += !odd ? upper : cur;
    acc[1] += odd ? upper : cur;
    return acc;
  }, ["", ""]);
}
Collapse
not_jffrydsr profile image
@nobody

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

Collapse
aminnairi profile image
Amin

Elm

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

    else
        character


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


capitalize : String -> ( String, String )
capitalize string =
    ( capitalizeIf even string, capitalizeIf odd string ) 
Collapse
not_jffrydsr profile image
@nobody

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.

Collapse
aminnairi profile image
Amin

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.

Collapse
craigmc08 profile image
Craig McIlwrath

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) 
Collapse
avalander profile image
Avalander

Ooh, clever! I like it!

Collapse
savagepixie profile image
SavagePixie

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
    str
      |> String.split("", trim: true)
      |> Enum.with_index
      |> Enum.map(&_mapper/1)
      |> Enum.unzip
      |> _join
  end

  defp _mapper({ letter, idx })
    when is_even(idx) do
      { String.capitalize(letter), String.downcase(letter) }
    end
  defp _mapper({ letter, idx })
    when is_odd(idx) do
      { String.downcase(letter), String.capitalize(letter) }
    end
  defp _join({ a, b }), do: { Enum.join(a), Enum.join(b) }
end
Collapse
citizen428 profile image
Michael Kohl

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
Collapse
lordapple profile image
LordApple
#!/bin/sh

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}")
done

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

Here is some shit I wrote using shellscript

Collapse
ksyula profile image
Ksenia

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:
            cap_s_even+=s[i].upper()
            cap_s_odd+=s[i]
        else:
            cap_s_even+=s[i]
            cap_s_odd+=s[i].upper()
    return [cap_s_even, cap_s_odd]
Collapse
cipharius profile image
Valts Liepiņš

Solution in Haskell using folding:

import Data.Char (toUpper)

capitalize :: String -> [String]
capitalize str = folder skipCase <$> [("",0),("",1)] <*> pure str
  where
    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.

Collapse
nilbert profile image
Nilbert

Ruby

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"]
Collapse
jhermann profile image
Jürgen Hermann

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']

😳 😱

Collapse
muhimen123 profile image
Muhimen

This is the magic of python. Short. I just love it. 💗

Collapse
ravikiranjs profile image
Ravi Kiran

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('')];
}

capitalize('abcdef')