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

714 lines
21 KiB
Markdown

# 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:
```cs
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:
```txt
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:
```cs
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:
```txt
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:
```cs
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.
```txt
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:
```cs
Console.WriteLine($"Before: {pallets[0]}");
Array.Clear(pallets, 0, 2);
Console.WriteLine($"After: {pallets[0]}");
```
Verify your code should match the following code listing:
```cs
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:
```txt
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::
```cs
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:
```cs
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:
```txt
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.
```cs
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:
```cs
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.
```txt
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:
```cs
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:
```txt
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:
```cs
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:
```cs
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.
```txt
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:
```cs
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:
```txt
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:
```cs
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:
```cs
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:
```txt
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:
```cs
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:
```txt
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:
```cs
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:
```txt
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.