10 Ways LINQ Can Make Your C# Code Cleaner and More Expressive

Programming LINQ .NET C#

As C# developers, we often write code that processes collections, filters data, or transforms values. While traditional loops and conditional statements get the job done, they can make code verbose and harder to read. This is where LINQ (Language Integrated Query) shines for it allows us to express complex operations concisely while keeping our intentions clear.

In this post, we'll explore 10 practical examples where LINQ can replace traditional imperative code, making it more maintainable and expressive.

1. Converting a CSV line into an int array

A string of comma‑separated numbers is split, each part trimmed, parsed to an int, and added to a new array.

Without LINQ

string csv = "12, 7, 23, 5, 9";
if (string.IsNullOrWhiteSpace(csv))
    return Array.Empty<int>();

string[] parts = csv.Split(',');
int[] numbers = new int[parts.Length];
for (int i = 0; i < parts.Length; i++)
{
    string trimmed = parts[i].Trim();
    if (int.TryParse(trimmed, out int value))
        numbers[i] = value;
    else
        numbers[i] = 0; // fallback
}
return numbers;

With LINQ

string csv = "12, 7, 23, 5, 9";
return csv.Split(',')
          .Select(s => s.Trim())
          .Where(s => int.TryParse(s, out _))
          .Select(int.Parse)
          .ToArray();

2. Removing null or empty strings from a list

Iterate through the list, skip empty items, and add the rest to a new list.

Without LINQ

List<string> raw = new List<string> { "one", null, "", "two", "three", "" };
List<string> cleaned = new List<string>();
foreach (string item in raw)
{
    if (!string.IsNullOrEmpty(item))
        cleaned.Add(item);
}
return cleaned;

With LINQ

List<string> raw = new List<string> { "one", null, "", "two", "three", "" };
return raw.Where(s => !string.IsNullOrEmpty(s)).ToList();

3. Checking if All Elements Meet a Condition

A common task is verifying that every item in a list satisfies a predicate.

Without LINQ

bool allValid = true;
foreach (var item in items)
{
    if (item.Length < 3)
    {
        allValid = false;
        break;
    }
}

With LINQ

bool allValid = items.All(item => item.Length >= 3);

4. Calculating the average price of items

Loop over each item, sum the price, then divide by the count.

Without LINQ

List<Item> items = GetItems(); // Item has decimal Price
decimal sum = 0m;
foreach (Item item in items)
    sum += item.Price;

decimal avg = items.Count > 0 ? sum / items.Count : 0m;
return avg;

With LINQ

List<Item> items = GetItems();
return items.Any() ? items.Average(i => i.Price) : 0m;

5. Finding the first employee with a salary above a threshold

Iterate through the list and return the first match.

Without LINQ

List<Employee> employees = GetEmployees();
Employee highPaid = null;
foreach (Employee emp in employees)
{
  if (emp.Salary > 100000)
    {
        highPaid = emp;
        break;
    }
}
return highPaid;

With LINQ

List<Employee> employees = GetEmployees();
return employees.FirstOrDefault(e => e.Salary > 100000);

6. Shuffling a playlist of tracks

Swap elements randomly in a loop (Fisher‑Yates shuffle).

Without LINQ

bool allValid = true;
foreach (var item in items)
{
    if (item.Length < 3)
    {
        allValid = false;
        break;
    }
}

With LINQ

var shuffledTracks = tracks.OrderBy(x => Guid.NewGuid()).ToList();

7. Conditional Logic for Collection Processing

When logic branches based on collection state, nested loops become unwieldy without LINQ:

List<string> result = new List<string>();
foreach (var item in collection1)
{
    foreach (var other in collection2)
    {
        if (item.Matches(other))
        {
            result.Add(item + other);
        }
    }
}

With LINQ:

var result = collection1
    .SelectMany(item => collection2.Where(other => item.Matches(other)))
    .Select(combined => combined.Item1 + combined.Item2)
    .ToList();

8. Aggregating sales totals per region

Loop over sales records, accumulate amounts in a dictionary keyed by region.

Without LINQ

List<Sale> sales = GetSales(); // Sale has Region and Amount
Dictionary<string, decimal> totals = new Dictionary<string, decimal>();
foreach (Sale sale in sales)
{
    if (totals.ContainsKey(sale.Region))
        totals[sale.Region] += sale.Amount;
    else
        totals[sale.Region] = sale.Amount;
}
return totals;

With LINQ

List<Sale> sales = GetSales();
return sales.GroupBy(s => s.Region)
            .ToDictionary(g => g.Key, g => g.Sum(s => s.Amount));

9. Selecting Unique Values from a Collection

Removing duplicates often requires a HashSet or manual checks without LINQ:

List<string> uniqueItems = new List<string>();
foreach (string item in items)
{
    if (!uniqueItems.Contains(item))
    {
        uniqueItems.Add(item);
    }
}

With LINQ:

var uniqueItems = items.Distinct().ToList();

10. Transforming a List of Objects

When converting a list of one type to another, manual mapping is often used without LINQ:

List<string> names = new List<string>();
foreach (var user in users)
{
    names.Add(user.FirstName + " " + user.LastName);
}

With LINQ

var names = users.Select(user => $"{user.FirstName} {user.LastName}").ToList();

Final Thoughts

In each example, the classic imperative approach involved manual loops, conditionals, and temporary collections. LINQ lets you express the intent

  • filter this
  • project this
  • group by that

in a concise, declarative manner. Not only do the LINQ snippets read more clearly, but they also reduce boilerplate and the chance of subtle bugs.