Storing data with collections

If you need to store multiple values in a variable, then you can use a collection.

A collection is a data structure in memory that can manage multiple items in different ways, although all collections have some shared functionality.

There are three main assemblies and namespaces for collections:

  • System.Collections.dll assembly and System.Collections.Generic namespace: The types in this assembly and namespace were introduced in C# 2 with .NET 2.0 and are better because they allow you to specify the type you want to store (which is safer, faster, and more efficient).
  • System.Collections.Concurrent assembly and namespace: the types in this assembly and namespace are safe to use in multi-threaded scenarios (see Chapter 12, Improving Performance and Scalability with Multitasking).
  • System.Collections.Immutable assembly and namespace: the types in this assembly and namespace are designed for scenarios where the contents of the collection should never change.

All collections have a Count property to tell you how many items are in it. For example, if we had a collection named passengers, we could do this:

    int howMany = passengers.Count; 

All collections can be iterated using the foreach statement. To perform some action on all the items in the passengers' collection, we can do this:

    foreach (var passenger in passengers) 
    { 
      // do something with each passenger 
    } 

Understanding collections

There are several different collection categories: lists, dictionaries, stacks, queues, sets, and many other more specialized collections.

Lists

Lists are a good choice when you want to manually control the order of items in a collection. Each item in a list has a unique index (or position) that is automatically assigned. Items can be any type (although they should all be the same type) and items can be duplicated. Indexes are int types and start from 0, so the first item in a list is at index 0, as shown in the following table:

Index

Item

0

London

1

Paris

2

London

3

Sydney

If a new item (for example, Santiago) is inserted between London and Sydney, then index of Sydney is automatically incremented. Therefore, you must be aware that an item's index can change after inserting or removing items, as shown in the following table:

Index

Item

0

London

1

Paris

2

London

3

Santiago

4

Sydney

Dictionaries

Dictionaries are a good choice when each value (or item) has a unique subvalue (or a made-up value) that can be used as a key to quickly find the value in the collection later. The key must be unique. If you are storing a list of people, you can use a government-issued identity number as the key.

Think of the key as being like an index entry in a real-world dictionary. It allows you to quickly find the definition of a word because the words (for example, keys) are kept sorted, and if we know we're looking for the definition of Manatee, we would jump to the middle of the dictionary to start looking because the letter M is in the middle of the alphabet. Dictionaries in programming are similarly smart when looking something up.

Both the key and the value can be any type. This example uses strings for both:

Key

Value

BSA

Bob Smith

MW

Max Williams

BSB

Bob Smith

AM

Amir Mohammed

Stacks

Stacks are a good choice when you want to implement the last-in, first-out (LIFO) behavior. With a stack, you can only directly access the one item at the top of the stack, although you can enumerate to read through the whole stack of items. You cannot, for example, access the second item in a stack.

For example, word processors use a stack to remember the sequence of actions you have recently performed, and then when you press Ctrl + Z , it will undo the last action in the stack, and then the next last action, and so on.

Queues

Queues are a good choice when you want to implement the first-in, first out (FIFO) behavior. With a queue, you can only directly access the one item at the front of the queue, although you can enumerate to read through the whole queue of items. You cannot, for example, access the second item in a queue.

For example, background processes use a queue to process work items in the order that they arrive, just like people standing in line at the post office.

Sets

Sets are a good choice when you want to perform set operations between two collections. For example, you may have two collections of city names, and you want to know which names appear in both sets (known as the intersect between the sets).

Working with lists

Add a new console application project named Ch04_Lists.

At the top of the file, import the following namespaces:

    using System; 
    using System.Collections.Generic; 
    using static System.Console; 

In the Main method, type the following code that illustrates some of the common ways of working with lists:

Note

The angle brackets after the List<T> type is a feature of C# called generics. It's just a fancy term for making a collection strongly typed, that is, the compiler knows more specifically what type of object can be stored in the collection. Generics improve the performance and correctness of your code. Strong typed is different from statically typed. The old System.Collection types are statically typed to contain weakly typed System.Object items. The newer System.Collection.Generic types are statically typed to contain strongly typed <T> instances. Ironically, the term "generics" means a more specific static type!

    var cities = new List<string>(); 
    cities.Add("London"); 
    cities.Add("Paris"); 
    cities.Add("Milan"); 
    WriteLine("Initial list"); 
    foreach (string city in cities) 
    { 
      WriteLine($"  {city}"); 
    } 
    WriteLine($"The first city is {cities[0]}.");  
    WriteLine($"The last city is {cities[cities.Count - 1]}."); 
    cities.Insert(0, "Sydney"); 
    WriteLine("After inserting Sydney at index 0"); 
    foreach (string city in cities) 
    { 
      WriteLine($"  {city}"); 
    } 
    cities.RemoveAt(1); 
    cities.Remove("Milan"); 
    WriteLine("After removing two cities"); 
    foreach (string city in cities) 
    { 
      WriteLine($"  {city}"); 
    } 

Run the console application to see the output:

Initial list
London
Paris
Milan
The first city is London.
The last city is Milan.
After inserting Sydney at index 0
Sydney
London
Paris
 Milan
After removing two cities
Sydney
 Paris

Working with dictionaries

Add a new console application project named Ch04_Dictionaries.

Import the same namespaces as before.

In the Main method, type the following code that illustrates some of the common ways of working with dictionaries:

    var keywords = new Dictionary<string, string>(); 
    keywords.Add("int", "32-bit integer data type"); 
    keywords.Add("long", "64-bit integer data type"); 
    keywords.Add("float", "Single precision floating point number"); 
    WriteLine("Keywords and their definitions"); 
    foreach (KeyValuePair<string, string> item in keywords) 
    { 
      WriteLine($"  {item.Key}: {item.Value}"); 
    } 
    WriteLine($"The definition of long is {keywords["long"]}"); 

Run the application to view the output:

Keywords and their definitions
int: 32-bit integer data type
long: 64-bit integer data type
float: Single precision floating point number
The definition of long is 64-bit integer data type

Sorting collections

A List<T> class can be sorted by calling its Sort method (but remember that the indexes of each item will change).

Note

Sorting a list of strings or other built-in types works automatically, but if you create a collection of your own type, then that type must implement an interface named IComparable. You will learn how to do this in Chapter 7, Implementing Interfaces and Inheriting Classes.

A Dictionary<T>, Stack<T>, or Queue<T> class cannot be sorted because you wouldn't usually want that functionality, for example, you would never sort a queue of guests checking into a hotel. But sometimes, you might want to sort a dictionary or a set.

The differences between these sorted collections are often subtle, but can have an impact on the memory requirements and performance of your application, so it is worth putting effort into picking the most appropriate for your requirements.

Collection

Description

SortedDictionary<TKey, TValue>

This represents a collection of key/value pairs that are sorted on the key

SortedList<TKey, TValue>

This represents a collection of key/value pairs that are sorted by key, based on the associated IComparer<T> implementation

SortedSet<T>

This represents a collection of objects that is maintained in a sorted order

Using specialized collections

There are a few other collections for special situations.

Collection

Description

System.Collections.BitArray

This manages a compact array of bit values, which are represented as Booleans, where true indicates that the bit is on (1) and false indicates the bit is off (0)

System.Collections .Generics.LinkedList<T>

This represents a doubly-linked list where every item has a reference to its previous and next item

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.165.226