C# > Advanced C# > Collections and Generics > List<T>, Dictionary<TKey, TValue>, HashSet<T>
Advanced Collection Operations: LINQ and Custom Comparers
This example explores advanced operations on collections using LINQ (Language Integrated Query) and custom comparers. We'll demonstrate filtering, sorting, grouping, and custom sorting based on specific criteria, showcasing how to manipulate collections in powerful and flexible ways. This provides insights into leveraging LINQ and custom comparers for complex data manipulation tasks.
Introduction to LINQ
LINQ provides a unified way to query and manipulate data from various sources, including collections. It allows you to write concise and expressive code for filtering, sorting, grouping, and projecting data. It uses extension methods heavily to add querying functionalities to collection objects.
Filtering with LINQ
This example uses the Where
extension method to filter a list of numbers and extract only the even numbers. The n => n % 2 == 0
is a lambda expression that defines the filtering condition.
using System;
using System.Collections.Generic;
using System.Linq;
public class LINQFilteringExample
{
public static void Main(string[] args)
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Filter even numbers using LINQ
IEnumerable<int> evenNumbers = numbers.Where(n => n % 2 == 0);
Console.WriteLine("Even numbers:");
foreach (int number in evenNumbers)
{
Console.WriteLine(number);
}
}
}
Sorting with LINQ
This example uses the OrderBy
extension method to sort a list of names alphabetically. The name => name
lambda expression specifies the sorting key (in this case, the name itself).
using System;
using System.Collections.Generic;
using System.Linq;
public class LINQSortingExample
{
public static void Main(string[] args)
{
List<string> names = new List<string> { "Charlie", "Alice", "Bob", "David" };
// Sort names alphabetically using LINQ
IEnumerable<string> sortedNames = names.OrderBy(name => name);
Console.WriteLine("Sorted names:");
foreach (string name in sortedNames)
{
Console.WriteLine(name);
}
}
}
Grouping with LINQ
This example uses the GroupBy
extension method to group a list of products by their category. The p => p.Category
lambda expression specifies the grouping key (in this case, the product category). Each group is an IGrouping
which implements IEnumerable
and has a Key
property.
using System;
using System.Collections.Generic;
using System.Linq;
public class LINQGroupingExample
{
public static void Main(string[] args)
{
List<Product> products = new List<Product>
{
new Product { Name = "Apple", Category = "Fruit" },
new Product { Name = "Banana", Category = "Fruit" },
new Product { Name = "Carrot", Category = "Vegetable" },
new Product { Name = "Broccoli", Category = "Vegetable" }
};
// Group products by category using LINQ
var groupedProducts = products.GroupBy(p => p.Category);
Console.WriteLine("Grouped products:");
foreach (var group in groupedProducts)
{
Console.WriteLine("Category: " + group.Key);
foreach (Product product in group)
{
Console.WriteLine(" " + product.Name);
}
}
}
}
public class Product
{
public string Name { get; set; }
public string Category { get; set; }
}
Custom Comparers
This example demonstrates how to use a custom comparer (PersonAgeComparer
) to sort a list of Person
objects by their age. The IComparer
interface defines the Compare
method, which is used to compare two objects. This allows you to define custom sorting logic based on specific criteria.
using System;
using System.Collections.Generic;
using System.Linq;
public class CustomComparerExample
{
public static void Main(string[] args)
{
List<Person> people = new List<Person>
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 25 },
new Person { Name = "Charlie", Age = 35 }
};
// Sort people by age using a custom comparer
people.Sort(new PersonAgeComparer());
Console.WriteLine("Sorted people by age:");
foreach (Person person in people)
{
Console.WriteLine(person.Name + ": " + person.Age);
}
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class PersonAgeComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Age.CompareTo(y.Age);
}
}
Real-Life Use Case: E-commerce Product Catalog
Imagine an e-commerce product catalog. LINQ can be used to filter products by price range, sort products by popularity, or group products by brand. Custom comparers can be used to sort products based on user ratings or other custom criteria.
Best Practices
Interview Tip
Be prepared to discuss the advantages and disadvantages of using LINQ for collection manipulation. Understand how to create and use custom comparers for sorting. Know the common LINQ extension methods (Where
, OrderBy
, GroupBy
, Select
, etc.) and their use cases.
When to Use Them
Memory Footprint
LINQ operations generally create new collections or iterators, which can increase memory usage. Custom comparers themselves don't significantly increase memory footprint, but the sorting algorithms they are used with can have memory implications.
Alternatives
Array.Sort
): Can be used for simple sorting scenarios.
Pros
Cons
FAQ
-
Can I use LINQ with
Dictionary
?
Yes, you can use LINQ withDictionary
. You can query the dictionary'sKeys
,Values
, or the entire collection ofKeyValuePair
objects using LINQ extension methods. -
How can I improve the performance of LINQ queries on large collections?
Consider using appropriate indexing, filtering data early in the pipeline, and avoiding unnecessary iterations. Also, be mindful of deferred execution and avoid forcing enumeration prematurely when possible. For specific scenarios, consider using PLINQ for parallel execution. -
What happens if my custom comparer throws an exception?
If your custom comparer throws an exception during the sorting process, the sorting operation will be interrupted, and the exception will be propagated. Ensure your custom comparer handles potential errors gracefully.