Lesson 2
Character Frequency Encoding with String Manipulation in C#
Introduction

Hello! Are you ready for an exciting voyage into the wonderful realm of strings and data structures? Today, we will be assisting 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 alphabetical order. In other words, given a string word, for each character, if it's 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 the product of the ASCII value of the character and its frequency. Our task is to construct a list that contains 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. For this, we define a StringBuilder called nextString to store the result of the shift operation. We then iterate over each character of the input string. If a character is not z, we replace it with the next alphabetical character using char arithmetic and type casting. If it is z, we replace it with a.

Here's the updated function:

C#
1using System; 2using System.Text; 3using System.Collections.Generic; 4 5public class Solution 6{ 7 public List<int> CharacterFrequencyEncoding(string word) 8 { 9 StringBuilder nextString = new StringBuilder(); 10 foreach (char letter in word) 11 { 12 nextString.Append(letter == 'z' ? 'a' : (char)(letter + 1)); 13 }
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 start by initializing an empty dictionary of type Dictionary<char, int>, called frequencyDict. Then, we iterate over nextString. If the current character exists in frequencyDict, we increment its frequency by 1. If it doesn't exist, we add it to frequencyDict with a frequency of 1.

Incorporating this step into the function, our code now looks like this:

C#
1 public List<int> CharacterFrequencyEncoding(string word) 2 { 3 StringBuilder nextString = new StringBuilder(); 4 foreach (char letter in word) 5 { 6 nextString.Append(letter == 'z' ? 'a' : (char)(letter + 1)); 7 } 8 9 var frequencyDict = new Dictionary<char, int>(); 10 foreach (char letter in nextString.ToString()) 11 { 12 if (frequencyDict.ContainsKey(letter)) 13 { 14 frequencyDict[letter]++; 15 } 16 else 17 { 18 frequencyDict[letter] = 1; 19 } 20 }
Solution Building: Step 3 - Building the product list

Next, we calculate the numerical representation for each unique character. We initialize a List<int>, called combinedValues, to store these numbers. For each character in frequencyDict, we calculate the product of its ASCII representation and its frequency in nextString, and append this to combinedValues.

Here's the updated function:

C#
1 public List<int> CharacterFrequencyEncoding(string word) 2 { 3 StringBuilder nextString = new StringBuilder(); 4 foreach (char letter in word) 5 { 6 nextString.Append(letter == 'z' ? 'a' : (char)(letter + 1)); 7 } 8 9 var frequencyDict = new Dictionary<char, int>(); 10 foreach (char letter in nextString.ToString()) 11 { 12 if (frequencyDict.ContainsKey(letter)) 13 { 14 frequencyDict[letter]++; 15 } 16 else 17 { 18 frequencyDict[letter] = 1; 19 } 20 } 21 22 var combinedValues = new List<int>(); 23 foreach (var entry in frequencyDict) 24 { 25 combinedValues.Add((int)entry.Key * entry.Value); 26 }
Solution Building: Step 4 - Sorting the final values

The final step is to sort the list combinedValues in descending order. We use C#'s Sort function with a comparison function to achieve descending order. Here's our complete function:

C#
1 public List<int> CharacterFrequencyEncoding(string word) 2 { 3 StringBuilder nextString = new StringBuilder(); 4 foreach (char letter in word) 5 { 6 nextString.Append(letter == 'z' ? 'a' : (char)(letter + 1)); 7 } 8 9 var frequencyDict = new Dictionary<char, int>(); 10 foreach (char letter in nextString.ToString()) 11 { 12 if (frequencyDict.ContainsKey(letter)) 13 { 14 frequencyDict[letter]++; 15 } 16 else 17 { 18 frequencyDict[letter] = 1; 19 } 20 } 21 22 var combinedValues = new List<int>(); 23 foreach (var entry in frequencyDict) 24 { 25 combinedValues.Add((int)entry.Key * entry.Value); 26 } 27 28 combinedValues.Sort((a, b) => b - a); 29 return combinedValues; 30 } 31}
Solution Building: Step 5 - Adding a Main Method and Example for Execution

To allow users to run the code and see how it works in practice, we'll add a Main method. This method will serve as the entry point of the program, where we'll demonstrate the function with a sample input.

Here's the complete code including the Main method:

C#
1using System; 2using System.Text; 3using System.Collections.Generic; 4 5public class Solution 6{ 7 public List<int> CharacterFrequencyEncoding(string word) 8 { 9 StringBuilder nextString = new StringBuilder(); 10 foreach (char letter in word) 11 { 12 nextString.Append(letter == 'z' ? 'a' : (char)(letter + 1)); 13 } 14 15 var frequencyDict = new Dictionary<char, int>(); 16 foreach (char letter in nextString.ToString()) 17 { 18 if (frequencyDict.ContainsKey(letter)) 19 { 20 frequencyDict[letter]++; 21 } 22 else 23 { 24 frequencyDict[letter] = 1; 25 } 26 } 27 28 var combinedValues = new List<int>(); 29 foreach (var entry in frequencyDict) 30 { 31 combinedValues.Add((int)entry.Key * entry.Value); 32 } 33 34 combinedValues.Sort((a, b) => b - a); 35 return combinedValues; 36 } 37 38 public static void Main(string[] args) 39 { 40 Solution solution = new Solution(); 41 string input = "banana"; 42 List<int> output = solution.CharacterFrequencyEncoding(input); 43 44 Console.WriteLine($"Input: {input}"); 45 Console.WriteLine("Output: " + string.Join(", ", output)); 46 } 47}

When you run this program, it processes the example input "banana" and outputs the resultant list after character frequency encoding:

1Input: banana 2Output: 294, 222, 99

In this section, we added a Main method to test our implementation with the string "banana". The output confirms that the algorithm shifts each character accordingly, calculates the product of each character’s ASCII value and its frequency, and sorts the products in descending order. You can modify the input variable in the Main method to try out other examples.

Lesson Summary

Well done! You've successfully tackled an intricate problem that required you to exercise multiple topics such as string manipulation, dictionary processing, and list sorting in C#. This task underscored the importance of reusing already calculated values. I encourage you to apply what you've learned today to other tasks. There are many more exciting challenges 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.