Entry-7: Different Ways to Collections in C#
Tags: programmingtips, dotnet, csharp, productivity
Published: 2023-07-23 15:07:25


![Coding image by Safar Safarov on unsplash](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/500q6ymj8ad239h7wedw.jpg)

This short article discusses three different strategies for handling collections using C# language, where each strategy employs a unique looping approach to achieve the same result.



The implementations include a Foreach loop, a LINQ-based approach using the Select method, and a traditional For loop run on 1000 iterations. Let's analyze each strategy, including their execution times, memory usage, and CPU usage, to understand their performance characteristics.

Before we begin, some key terms to note

**Compile Time:**
Compile time refers to the duration it takes for the compiler to process the source code and generate executable machine code. During compilation, the compiler checks the code for syntax errors, performs optimizations, and translates it into machine-readable instructions. A shorter compile time indicates that the code is processed quickly and is ready for execution, which is desirable for development efficiency.

**Execution Time:**
Execution time, also known as runtime, is the time taken by a program to complete its execution once it starts running. It measures how long it takes for the program to execute all its statements and complete its tasks. A lower execution time means that the program runs faster, which is beneficial for applications that require quick responses and high performance.

**Memory Usage:**
Memory usage represents the amount of memory (RAM) that a program consumes while it is running. It indicates the space required to store data, variables, and program instructions during execution. Lower memory usage is generally preferred, especially for resource-constrained environments or when dealing with large datasets, as it reduces the risk of memory-related issues like crashes or slowdowns.

**CPU Time:**
CPU time measures the total amount of time the central processing unit (CPU) spends executing a program. It includes the time the CPU spends processing instructions for the program and any time spent waiting for external resources like I/O operations. A lower CPU time indicates that the program is using the CPU efficiently and is not overly taxing the processor, leading to better overall system performance.


### Strategies

1. Foreach Doubling Strategy:

This strategy utilizes a foreach loop to iterate through the input list and double each element. The resulting doubled numbers are stored in a new list, which is then returned. This approach offers simplicity in syntax and is easy to read.

- Compile Time: 0.156s
- Execution Time: 0.016s
- Memory Usage: 96kb
- CPU Time: 0.016s

```csharp
public List<int> ForeachDoublingStrategy(List<int> numbers)
{
   List<int> doubledNumbers = new List<int>();
   foreach (int num in numbers)
   {
       doubledNumbers.Add(num * 2);
   }
   return doubledNumbers;
}

```

2. LINQ Doubling Strategy:

In this strategy, we leverage LINQ's Select method, which provides a concise way to perform the doubling operation on each element of the input list. The Select method returns an IEnumerable<int> that is then converted to a `List<int>` using the `ToList()` method.

- Compile Time: 0.172s
- Execution Time: 0.016s
- Memory Usage: 152kb
- CPU Time: 0.016s

```csharp
public List<int> LinqDoublingStrategy(List<int> numbers)
{
   return numbers.Select(num => num * 2).ToList();
}

```

3. For Loop Doubling Strategy:

This strategy employs a traditional `for` loop to iterate through the input list and double each element. The doubled numbers are added to a new list, which is returned after the loop completes.

- Last Run: 3:26:47 pm
- Compile Time: 0.172s
- Execution Time: 0.016s
- Memory Usage: 104kb
- CPU Time: 0.031s

```csharp
public List<int> ForLoopDoublingStrategy(List<int> numbers)
{
   List<int> doubledNumbers = new List<int>();
   for (int i = 0; i < numbers.Count; i++)
   {
       doubledNumbers.Add(numbers[i] * 2);
   }
   return doubledNumbers;
}

```

Each of the provided strategies use a sample which effectively doubles the elements in the input list of integers. 

The `Foreach` and `For Loop` strategies offer similar performance, with `Foreach` consuming slightly less memory. On the other hand, the LINQ-based `Select` approach uses a bit more memory but remains concise and easy to maintain. 

To decide on the best strategy, consider the specific requirements of the application. If memory usage is a significant concern, especially for large datasets, the `Foreach` or `For Loop` strategy might be more suitable. These approaches can efficiently process data without creating additional memory overhead.

On the other hand, if code readability, simplicity, and ease of maintenance are higher priorities, the LINQ-based approach could be the better choice. The `Select` method offers an elegant way to perform the doubling operation, making the code more expressive and easier to manage.

Ultimately, it is essential to balance code readability, simplicity, and memory efficiency based on the specific needs of the application. For critical scenarios with memory constraints, profiling different strategies with representative data can help determine the most appropriate choice. Keep in mind that different situations may warrant different strategies, so it is crucial to assess the trade-offs and select the best approach accordingly.

Profiler used -

* https://dotnetfiddle.net/KW7EW4

**External Links**

- **Twitter**: [@benny_wayn](https://twitter.com/etieno_u)
- **LinkedIn**: [Ibenge-uforo](https://www.linkedin.com/in/ibenge-uforo/)
- **Ongoing** **Research**: [Social Survey](https://docs.google.com/forms/d/e/1FAIpQLScKBo1VQvEVpvxKbOamhWq02uQU8HlgUPq576F-LD3yTljkwg/viewform)