1

I got a task on code wars.

The task is

In this simple Kata your task is to create a function that turns a string into a Mexican Wave. You will be passed a string and you must return that string in an array where an uppercase letter is a person standing up.

Rules are

  1. The input string will always be lower case but maybe empty.

  2. If the character in the string is whitespace then pass over it as if it was an empty seat

Example

wave("hello") => []string{"Hello", "hEllo", "heLlo", "helLo", "hellO"}

So I have found the solution but I want to understand the logic of it. Since its so minimalistic and looks cool but I don't understand what happens there. So the solution is

fun wave(str: String) = str.indices.map { str.take(it) + str.drop(it).capitalize() }.filter { it != str }

Could you please explain?

Bob Redity
  • 529
  • 5
  • 14

2 Answers2

4

str.indices just returns the valid indices of the string. This means the numbers from 0 to and including str.length - 1 - a total of str.length numbers.

Then, these numbers are mapped (in other words, transformed) into strings. We will now refer to each of these numbers as "it", as that is what it refers to in the map lambda.

Here's how we do the transformation: we first take the first it characters of str, then combine that with the last str.length - it characters of str, but with the first of those characters capitalized. How do we get the last str.length - it characters? We drop the first it characters.

Here's an example for when str is "hello", illustrated in a table:

it str.take(it) str.drop(it) str.drop(it).capitalize() Combined
0 hello Hello Hello
1 h ello Ello hEllo
2 he llo Llo heLlo
3 hel lo Lo helLo
4 hell o O hellO

Lastly, the solution also filters out transformed strings that are the same as str. This is to handle Rule #2. Transformed strings can only be the same as str if the capitalised character is a whitespace (because capitalising a whitespace character doesn't change it).

Side note: capitalize is deprecated. For other ways to capitalise the first character, see Is there a shorter replacement for Kotlin's deprecated String.capitalize() function?

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • A table and everything, very nice! – cactustictacs Jul 27 '22 at 22:51
  • thanks a lot. Could you please explain one more thing. How this part works `str.take(it) + str.drop(it).capitalize()` . So we I don't understand what happens when `take triggers` and why `+` is there and what characters are capitalized here? – Bob Redity Jul 28 '22 at 12:47
  • @BobRedity Please see the table. `take` takes the first `it` characters. `drop` removes the first `it` characters. `+` combines/joins the two parts together. `capitalize()` capitalises the *first* character of `str.drop(it)`. – Sweeper Jul 28 '22 at 12:52
0

Here's another way you could do it:

fun wave2(str: String) = str.mapIndexed { i, c -> str.replaceRange(i, i + 1, c.uppercase()) }
    .filter { it.any(Char::isUpperCase) }

The filter on the original is way more elegant IMO, this is just as an example of how else you might check for a condition. replaceRange is a way to make a copy of a string with some of the characters changed, in this case we're just replacing the one at the current index by uppercasing what's already there. Not as clever as the original, but good to know!

cactustictacs
  • 17,935
  • 2
  • 14
  • 25