ms_learn_csharp/022_array_operations/022_csharp.md
2024-07-31 22:38:31 -04:00

21 KiB

Perform operations on arrays using helper methods in C#

Introduction

Suppose you are a software developer on a team assigned to work with a logistics company. They have many needs for gathering and organizing their business data. Projects vary from tracking and reporting inventory, enabling specific data to be passed to and from business partners, and identifying possible fraudulent orders. Each project is different, but all require the processing of data. In these projects the applications will be performing data operations such as to add, delete, sort, combine, calculate, validate and format output.

In this module, you'll use C# arrays to allow you to store sequences of values in a single data structure. Once you have data in an array, you can manipulate the order and the contents of the array. Furthermore, you'll be able to perform powerful string operations using array helper methods.

With the use of several helper methods, you'll sort the data or reverse the order of the data. You'll clear out the items in the array and resize the array to add new items. You'll convert a string into an array by splitting it into smaller strings each time you encounter a character like a comma. You'll also split a string into an array of characters. Finally, you'll join all of the elements of an array into a single string.

Learning objectives

In this module you will:

  • Sort and reverse the order of array elements.
  • Clear and resize the elements of an array.
  • Split a string into an array of strings or characters (chars).
  • Join array elements into a string.

Exercise - Discover Sort() and Reverse()

The Array class contains methods that you can use to manipulate the content, arrangement, and size of an array. In this exercise, you'll write code that performs various operations on an array of pallet identifiers. Your code could be the start of an application to track and optimize the usage of pallets for the company.

Create an array of pallets, then sort them

Type the following code into the editor:

string[] pallets = { "B14", "A11", "B12", "A13" };
Console.WriteLine("Sorted...");
Array.Sort(pallets);
foreach (var pallet in pallets) {
    Console.WriteLine($"-- {pallet}");
}

Take a minute to review the Array.Sort(pallets); line from the previous code you added.

Here you're using the Sort() method of the Array class to sort the items in the array alphanumerically.

The Program.cs file must be saved before building or running the code.

At the Terminal command prompt, to run your code, type dotnet run and then press Enter.

You should see the following output:

Sorted...
-- A11
-- A13
-- B12
-- B14

Reverse the order of the pallets

To reverse the order of the pallets using the Array.Reverse() method, update your code as follows:

string[] pallets = { "B14", "A11", "B12", "A13" };
Console.WriteLine("Sorted...");
Array.Sort(pallets);
foreach (var pallet in pallets) {
    Console.WriteLine($"-- {pallet}");
}

Console.WriteLine("");
Console.WriteLine("Reversed...");
Array.Reverse(pallets);
foreach (var pallet in pallets) {
    Console.WriteLine($"-- {pallet}");
}

Focus on the line of code Array.Reverse(pallets); line from the previous code you added.

Here, you're using the Reverse() method of the Array class to reverse the order of items.

Save your code file, and then run your code. You should see the following output:

Sorted...
-- A11
-- A13
-- B12
-- B14

Reversed...
-- B14
-- B12
-- A13
-- A11

Recap

Here's a few important ideas that you covered in this unit:

  • The Array class has methods that can manipulate the size and contents of an array.
  • Use the Sort() method to manipulate the order based on the given data type of the array.
  • Use the Reverse() method to flip the order of the elements in the array.

Exercise - Explore Clear() and Resize()

As you continue building a pallet tracker for the logistics company, suppose you also need track new pallets and remove old pallets from tracking. How can you accomplish creating tracking functionality for adding and removing pallets?

Use array methods to clear and resize an array

The Array.Clear() method allows you to remove the contents of specific elements in your array and replace it with the array default value. For example, in a string array the element value cleared is replaced with null, when you clear a int array element the replacement is done with 0 (zero).

The Array.Resize() method adds or removes elements from your array.

Delete or use the line comment operator // to comment out all of the code from the previous exercises.

Update your code in the editor as follows:

string[] pallets = { "B14", "A11", "B12", "A13" };
Console.WriteLine("");

Array.Clear(pallets, 0, 2);
Console.WriteLine($"Clearing 2 ... count: {pallets.Length}");
foreach (var pallet in pallets) {
    Console.WriteLine($"-- {pallet}");
}

Take a minute to focus on the line of code Array.Clear(pallets, 0, 2);.

Here you're using the Array.Clear() method to clear the values stored in the elements of the pallets array starting at index 0 and clearing 2 elements.

The Program.cs file must be saved before building or running the code.

At the Terminal command prompt, to run your code, type dotnet run and then press Enter.

When you run the code, you'll see that the values stored in the first two elements of the array have been cleared out. In the Length property and the foreach statement, the elements still exist, but they're now empty.

Clearing 2 ... count: 4
-- 
-- 
-- B12
-- A13

Empty string versus null

When you use Array.Clear(), the elements that were cleared no longer reference a string in memory. In fact, the element points to nothing at all. pointing to nothing is an important concept that can be difficult to grasp at first.

What if you attempt to retrieve the value of an element that was affected by the Array.Clear() method, could you do it?

Access the value of a cleared element

Two approaches are needed to determine the value of a cleared element to see how the C# compiler works with a null value.

Insert new code lines around the Array.Clear(pallets, 0, 2); code line as follows:

Console.WriteLine($"Before: {pallets[0]}");
Array.Clear(pallets, 0, 2);
Console.WriteLine($"After: {pallets[0]}");

Verify your code should match the following code listing:

string[] pallets = { "B14", "A11", "B12", "A13" };
Console.WriteLine("");

Console.WriteLine($"Before: {pallets[0]}");
Array.Clear(pallets, 0, 2);
Console.WriteLine($"After: {pallets[0]}");

Console.WriteLine($"Clearing 2 ... count: {pallets.Length}");
foreach (var pallet in pallets) {
    Console.WriteLine($"-- {pallet}");
}

Save your code file, and then run your code.

You should see the following output:

Before: B14
After:
Clearing 2 ... count: 4
--
--
-- B12
-- A13

If you focus on the line of output After: , you might think that the value stored in pallets[0] is an empty string. However, the C# Compiler implicitly converts the null value to an empty string for presentation.

Call a string helper method on a cleared element

To prove that the value stored in pallets[0] after being cleared is null, you 'll modify the code example to call the ToLower() method on pallets[0]. If it's a string, it should work fine. But if it's null, it should cause the code to throw an exception.

To call the ToLower() method each time you attempt to write pallets[0] to the console, update your code as follows::

Console.WriteLine($"Before: {pallets[0].ToLower()}");
Array.Clear(pallets, 0, 2);
Console.WriteLine($"After: {pallets[0].ToLower()}");

Make sure your code matches the following code listing:

string[] pallets = { "B14", "A11", "B12", "A13" };
Console.WriteLine("");

Console.WriteLine($"Before: {pallets[0].ToLower()}");
Array.Clear(pallets, 0, 2);
Console.WriteLine($"After: {pallets[0].ToLower()}");

Console.WriteLine($"Clearing 2 ... count: {pallets.Length}");
foreach (var pallet in pallets) {
    Console.WriteLine($"-- {pallet}");
}

Save your code file, and then run your code. This time, when you run the code, you'll see a large error message. If you parse through the text, you'll see the following message:

System.NullReferenceException: Object reference not set to an instance of an object.

This exception is thrown because the attempt to call the method on the contents of the pallets[0] element happens before the C# Compiler has a chance to implicitly convert null to an empty string.

The moral of the story is that Array.Clear() will remove an array element's reference to a value if one exists. To fix this, you might check for null before attempt to print the value.

To avoid the error, add an if statement before accessing an array element that is potentially null.

if (pallets[0] != null)
    Console.WriteLine($"After: {pallets[0].ToLower()}");

Resize the array to add more elements

Next, rework the code listing from Step 1 to include code to resize the array. When complete, your code should match the following code listing:

string[] pallets = { "B14", "A11", "B12", "A13" };
Console.WriteLine("");

Array.Clear(pallets, 0, 2);
Console.WriteLine($"Clearing 2 ... count: {pallets.Length}");
foreach (var pallet in pallets) {
    Console.WriteLine($"-- {pallet}");
}

Console.WriteLine("");
Array.Resize(ref pallets, 6);
Console.WriteLine($"Resizing 6 ... count: {pallets.Length}");

pallets[4] = "C01";
pallets[5] = "C02";

foreach (var pallet in pallets) {
    Console.WriteLine($"-- {pallet}");
}

Take a few minutes to focus on the line Array.Resize(ref pallets, 6);.

Here, you're calling the Resize() method passing in the pallets array by reference, using the ref keyword. In some cases, methods require you pass arguments by value (the default) or by reference (using the ref keyword). The reasons why this is necessary requires a long and complicated explanation about of how objects are managed in .NET. Unfortunately, that is beyond the scope of this module. When in doubt, you're recommended to look at Intellisense or Microsoft Learn for examples on how to properly call a given method.

In this case, you're resizing the pallets array from four elements to 6. The new elements are added at the end of the current elements. The two new elements will be null until you assign a value to them.

Save your code file, and then run your code. When you run the code, you should see the following output.

Clearing 2 ... count: 4
-- 
-- 
-- B12
-- A13

Resizing 6 ... count: 6
-- 
-- 
-- B12
-- A13
-- C01
-- C02

Resize the array to remove elements

Conversely, you can remove array elements using Array.Resize().

Update your code in the editor as follows:

string[] pallets = { "B14", "A11", "B12", "A13" };
Console.WriteLine("");

Array.Clear(pallets, 0, 2);
Console.WriteLine($"Clearing 2 ... count: {pallets.Length}");
foreach (var pallet in pallets) {
    Console.WriteLine($"-- {pallet}");
}

Console.WriteLine("");
Array.Resize(ref pallets, 6);
Console.WriteLine($"Resizing 6 ... count: {pallets.Length}");

pallets[4] = "C01";
pallets[5] = "C02";

foreach (var pallet in pallets) {
    Console.WriteLine($"-- {pallet}");
}

Console.WriteLine("");
Array.Resize(ref pallets, 3);
Console.WriteLine($"Resizing 3 ... count: {pallets.Length}");

foreach (var pallet in pallets) {
    Console.WriteLine($"-- {pallet}");
}

Save your code file, and then run your code. When you run the code, you should see the following output:

Clearing 2 ... count: 4
--
--
-- B12
-- A13

Resizing 6 ... count: 6
--
--
-- B12
-- A13
-- C01
-- C02

Resizing 3 ... count: 3
--
--
-- B12

Notice that calling Array.Resize() didn't eliminate the first two null elements. Rather, it removed the last three elements. Notably, last three elements were removed even though they contained string values.

Can you remove null elements from an array?

If the Array.Resize() method doesn't remove empty elements from an array, is there another helper method that will do the job automatically? No. The best way to empty elements from an array would be to count the number of non-null elements by iterating through each item and increment a variable (a counter). Next, you would create a second array that is the size of the counter variable. Finally, you would loop through each element in the original array and copy non-null values into the new array.

Recap

Here's a few important ideas that you covered in this unit:

  • Use the Clear() method to empty the values out of elements in the array.
  • Use the Resize() method to change the number of elements in the array, removing or adding elements from the end of the array.
  • New array elements and cleared elements are null, meaning they don't point to a value in memory.

Exercise

Discover Split() and Join()

As you continue your development work for a logistics company, you begin building a series of small applications. Combined, the applications take data from one partner's system, modify the data, then pass it to an internal system in the format it requires.

To perform data transformation, you need to accept incoming data as a string, parse it into smaller data elements, then manipulate it to match different format required. How can you parse the string data into smaller data elements?

String data type's Array methods

The variables of type string have many built-in methods that convert a single string into either an array of smaller strings, or an array of individual characters.

When processing data from other computer systems, sometimes it's formatted or encoded in a way that's not useful for your purposes. In these cases, you can use the string data type's Array methods to parse a string into an array.

Use the ToCharArray() to reverse a string

Delete or use the line comment operator // to comment out all of the code from the previous exercises.

Update your code as follows:

string value = "abc123";
char[] valueArray = value.ToCharArray();

Here you use the ToCharArray() method to create an array of char, each element of the array has one character of the original string.

Reverse, then combine the char array into a new string

Next, you reverse the order of the chars in the array, then use the Write method to combine them back into a single output.

Update your code as follows:

string value = "abc123";
char[] valueArray = value.ToCharArray();
Array.Reverse(valueArray);
string result = new string(valueArray);
Console.WriteLine(result);

The expression new string(valueArray) creates a new empty instance of the System.String class (which is the same as the string data type in C#) and passes in the char array as a constructor.

Note
What is the new keyword? How is the System.String class related to the string data type in C#? What is a constructor? All great questions that unfortunately are out of scope for this module. You are recommended to keep learning about the .NET Class Library as well as classes and objects in C# to fully understand what is going on behind the scenes with this expression of cod e. For now, use a search engine and Microsoft Documentation to find examples you can use in situations like this where you know you want to perform a conversion but are not sure how to do it using C#.

The Program.cs file must be saved before building or running the code.

At the Terminal command prompt, to run your code, type dotnet run and then press Enter.

321cba

Combine all of the chars into a new comma-separated-value string using Join()

Perhaps you need to separate each element of the char array using a comma, as is common when working with data that is represented as ASCII text. To do that, you'll comment out the line of code you added in Step 2 and use the String class' Join() method, passing in the char you want to delimit each segment (the comma) and the array itself.

Update your code as follows:

string value = "abc123";
char[] valueArray = value.ToCharArray();
Array.Reverse(valueArray);
// string result = new string(valueArray);
string result = String.Join(",", valueArray);
Console.WriteLine(result);

Save your code file, and then run your code.

You should see the following output:

3,2,1,c,b,a

Split() the comma-separated-value string into an array of strings

To complete the code, you use the Split() method, which is for variables of type string to create an array of strings.

Add the following lines of code at the bottom of the file:

string[] items = result.Split(',');
foreach (string item in items) {
    Console.WriteLine(item);
}

Take a minute to review the previous code.

The comma is supplied to .Split() as the delimiter to split one long string into smaller strings. The code then uses a foreach loop to iterate through each element of the newly created array of strings, items.

Check that your code now appears as follows:

string value = "abc123";
char[] valueArray = value.ToCharArray();
Array.Reverse(valueArray);
// string result = new string(valueArray);
string result = String.Join(",", valueArray);
Console.WriteLine(result);

string[] items = result.Split(',');
foreach (string item in items) {
    Console.WriteLine(item);
}

When you run the code, you'll see the following output:

3,2,1,c,b,a
3
2
1
c
b
a

The items array created using string[] items = result.Split(','); is used in the foreach loop and displays the individual characters from the original string contained in the value variable.

Recap

Here's a few things to remember when working with strings and arrays:

  • Use methods like ToCharArray() and Split() to create an array
  • Use methods like Join(), or create a new string passing in an array of char to turn the array back into a single string

Exercise

Complete a challenge to reverse words in a sentence

Code challenges reinforce what you've learned and help you gain some confidence before continuing on.

Many times you'll need to combine several of the ideas covered in this module into a single solution. You should work to decompose a larger problem into lots of mini-problems, then use the various ideas in this module to solve each mini-problem.

Write code to reverse each word in a message

Update your code in the editor as follows:

string pangram = "The quick brown fox jumps over the lazy dog";

Write the code necessary to reverse the letters of each word in place and display the result.

In other words, don't just reverse every letter in the variable pangram. Instead, you'll need to reverse just the letters in each word, but print the reversed word in its original position in the message.

Your code must produce the following output:

ehT kciuq nworb xof spmuj revo eht yzal god

Important
This is a particularly difficult challenge. You will need to combine many of the concepts you learned in this exercise, including the use of the Split(), ToCharArray(), Array.Reverse(), and String.Join(). You'll also need to create multiple arrays, and at least one iteration statement.

Good luck! Just keep decomposing the problem into small steps, then solve that particular step before moving to the next.

Whether you get stuck and need to peek at the solution or you finish successfully, continue on to view a solution to this challenge.


Exercise

Complete a challenge to parse a string of orders, sort the orders and tag possible errors

Data comes in many formats. In this challenge you have to parse the individual "Order IDs", and output the "OrderIDs" sorted and tagged as "Error" if they aren't exactly four characters in length.

Add the following code to get the data for the challenge:

string orderStream = "B123,C234,A345,C15,B177,G3003,C235,B179";

Notice in the previous code, the orderStream variable contains a string of multiple Order IDs separated by commas

Add code below the previous code to parse the "Order IDs" from the string of incoming orders and store the "Order IDs" in an array

Add code to output each "Order ID" in sorted order and tag orders that aren't exactly four characters in length as "- Error"

Save and run your code

Your code must produce the following output:

A345
B123
B177
B179
C15     - Error
C234
C235
G3003   - Error

Whether you get stuck and need to peek at the solution or you finish successfully, continue on to view a solution to this challenge.


Summary

In this module, you completed exercises using helper methods to use arrays more effectively to:

  • Clear items in an array, learning the elements are set to null, using the Array.Clear() method.
  • Resize an array to add and remove elements using the Array.Resize() method.
  • Convert a string into an array using String.Split() specifying a string separator character to produce a value in the returned array.
  • Combine all of the elements of an array into a single string using the String.Join() method.

The array helper methods allowed you to work flexibly with data in the applications. Without these features, arrays would be less useful.