Lesson 2
Advanced String Manipulation and Frequency Analysis in Kotlin
Introduction

Hello! Are you ready for an exciting voyage into the wonderful realm of strings and data structures? Today, we will assist Alice, an aspiring cryptographer, with an intriguing string manipulation task. She loves playing with strings and has come up with a unique string encoding scheme. I assure you this will be an enlightening journey that will stretch your programming muscles. Let's get started!

Task Statement

Alice has devised a unique way of encoding words. She takes a word and replaces each character with the next character in the alphabetical order. In other words, given a string word, for each character, if it is not z, she replaces it with the character that comes next alphabetically. For the character z, she replaces it with a.

Another element of Alice's algorithm involves frequency analysis. After shifting the characters, she counts the frequency of each character in the new string. Then, she creates an association of each character with its frequency and ASCII value. Each character maps to a number, which is a product of the ASCII value of the character and its frequency. Our task is to construct a list containing these products, sorted in descending order.

Example

For the input string "banana", the output should be [294, 222, 99].

The string "banana" will be shifted to "cbobob".

Calculating the product of frequency and ASCII value for each character:

  • The ASCII value for c is 99; it appears once in the string, so its product is 99 * 1 = 99.
  • The ASCII value for b is 98; it appears three times in the string, so its product is 98 * 3 = 294.
  • The ASCII value for o is 111; it appears twice in the string, so its product is 111 * 2 = 222.

Collecting these products into a list gives [99, 294, 222]. Sorting this list in descending order results in [294, 222, 99].

Solution Building: Step 1 - Mapping each character to the next alphabetical character

Our first step involves mapping each character of the input string to the next alphabetical character. In Kotlin, we use a StringBuilder for mutable strings, which allows us to efficiently append each shifted character. To achieve this, we iterate over each character of the input string using Kotlin's forEach method. If a character is not z, we replace it with the next alphabetical character using letter + 1. If it is z, we replace it with a.

Here's the updated function in Kotlin:

Kotlin
1fun characterFrequencyEncoding(word: String): String { 2 val nextString = StringBuilder() 3 word.forEach { letter -> 4 nextString.append(if (letter == 'z') 'a' else (letter + 1)) 5 } 6 return nextString.toString() 7}
Solution Building: Step 2 - Counting the frequency of characters in `nextString`

The next step is to track the frequency of each character in nextString. We initialize a mutable map frequencyMap using Kotlin's mutableMapOf<Char, Int>(). Then, we iterate over nextString. For each character, we use getOrElse to retrieve the current frequency or default to 0, and increment it by 1.

Here's the Kotlin code for this step:

Kotlin
1fun countFrequency(nextString: String): MutableMap<Char, Int> { 2 val frequencyMap = mutableMapOf<Char, Int>() 3 nextString.forEach { letter -> 4 frequencyMap[letter] = frequencyMap.getOrElse(letter) { 0 } + 1 5 } 6 return frequencyMap 7}
Solution Building: Step 3 - Building the product list

Next, we calculate the numerical representation for each unique character. We use Kotlin's mutableListOf<Int>() to store these numbers as combinedValues. For each character in frequencyMap, we calculate the product of its ASCII value and its frequency in nextString, then append this to combinedValues.

Here's the Kotlin function for this:

Kotlin
1fun buildProductList(frequencyMap: Map<Char, Int>): MutableList<Int> { 2 val combinedValues = mutableListOf<Int>() 3 frequencyMap.forEach { (key, value) -> 4 combinedValues.add(key.toInt() * value) 5 } 6 return combinedValues 7}
Solution Building: Step 4 - Sorting the final values

The final step is to sort the list combinedValues in descending order. In Kotlin, we use the sortDescending() method to accomplish this.

Here's the complete Kotlin function:

Kotlin
1fun characterFrequencyEncoding(word: String): List<Int> { 2 // Step 1: Mapping each character to the next alphabetical character 3 val nextString = StringBuilder() 4 word.forEach { letter -> 5 nextString.append(if (letter == 'z') 'a' else (letter + 1)) 6 } 7 8 // Step 2: Counting the frequency of characters in nextString 9 val frequencyMap = mutableMapOf<Char, Int>() 10 nextString.toString().forEach { letter -> 11 frequencyMap[letter] = frequencyMap.getOrElse(letter) { 0 } + 1 12 } 13 14 // Step 3: Building the product list 15 val combinedValues = frequencyMap.map { (key, value) -> 16 key.toInt() * value 17 }.toMutableList() 18 19 // Step 4: Sorting the final values in descending order 20 combinedValues.sortDescending() 21 22 // Return the sorted list 23 return combinedValues 24} 25 26fun main() { 27 val word = "banana" 28 val result = characterFrequencyEncoding(word) 29 println(result.joinToString(" ")) 30 // Prints: 31 // 294 222 99 32}
Lesson Summary

Well done! You've successfully tackled an intricate problem that required you to exercise multiple topics such as string manipulation, map processing, and list sorting. This task underscored the importance of reusing already calculated values. I encourage you to apply what you've learned today to other tasks. Many more exciting challenges are waiting for you in the upcoming practice sessions. Happy coding!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.