LINQ

Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query capabilities directly into the C# language. With LINQ, a query is a first-class language construct, just like classes, methods, and events.

The LINQ to Objects works with any collection that implements the IEnumerable<T> interface.

collections2 #direction: right #spacing: 10 #gravity: .8 #arrowSize: 4 #title: collections2 [IEnumerable| IEnumerator GetEnumerator ()] <:-- [IEnumerable<out T>| IEnumerator<out T> GetEnumerator ()] [IEnumerable<out T>] <:-- [IOrderedEnumerable<out TElement>| CreateOrderedEnumerable<TKey>( Func<out TElement,TKey> keySelector, IComparer<TKey>? comparer, bool descending)] [IEnumerable<out T>] <:-- [IGrouping<out TKey,out TElement>| TKey Key { get\; }] <:-- [ILookup<TKey,TElement>| int Count { get\; } IEnumerable<TElement> this\[TKey key\] { get\; }| bool Contains (TKey key)] [IEnumerable<out T>] <:-- [IQueryable<out T>] <:-- [IOrderedQueryable<out T>] [IEnumerable] <:-- [IQueryable] <:-- [IQueryable<out T>] [IQueryable | Type ElementType { get\; } Expression Expression { get\; } IQueryProvider Provider { get\; }] [IEnumerator| object Current { get\; } bool MoveNext() void Reset()] [IEnumerator] <:-- [IEnumerator<out T>| T Current { get\; }] [IDisposable| void Dispose()] [IDisposable] <:-- [IEnumerator<out T>] IEnumerable IEnumerator GetEnumerator () IEnumerable<out T> IEnumerator<out T> GetEnumerator () IOrderedEnumerable<out TElement> CreateOrderedEnumerable<TKey>( Func<out TElement,TKey> keySelector, IComparer<TKey>? comparer, bool descending) IGrouping<out TKey,out TElement> TKey Key { get; } ILookup<TKey,TElement> int Count { get; } IEnumerable<TElement> this[TKey key] { get; } bool Contains (TKey key) IQueryable<out T> IOrderedQueryable<out T> IQueryable Type ElementType { get; } Expression Expression { get; } IQueryProvider Provider { get; } IEnumerator object Current { get; } bool MoveNext() void Reset() IEnumerator<out T> T Current { get; } IDisposable void Dispose()

The IEnumerable<T> interface

Filtering

var customerOrders = Orders.Where(order => order.CustomerId == 66);

Select with anonymus type

var ordersWithCost = Orders.Select(order => new
{
    OrderId = order.Id,
    Cost = order.Cost,
});

Distinct

//The Distinct method requires equality implementation on the class or 
//an IEqualityComparer as parameter
var uniqueNames = customer.Distinct((customerComparer);

//DistinctBy requires a lambda
var uniqueNames = customer.DistinctBy(√ => √.Name); 

Ordering

var ascendingOrder = orders.OrderBy(order => order.Cost);
var descendingOrder = orders.OrderByDescending(order => order.Cost);

var multipleOdering = orders.OrderBy(order => order.Cost).ThenBy(order => order.CustomerId);

Note: Result will be an IOrderedEnumerable<TElement>.

Join

var joined = customers.Join(orders, 
                            customer => customer.Id, 
                            order => order.CustomerId
                            (customer, order) => new
                            {
                                CustomerId = customer.Id,
                                Name = customer.Name,
                                Cost = order.Cost, 
                            });

Grouping

var grouped = orders.GroupBy(order => CustomerId);

Note: Result will be an IGrouping<TKey,TElement>

Lookup

var packagesByCompany = packages.ToLookup(oder => oder.Date,  order => order.id); 

Note: Result will be an ILookup<TKey,TElement>, which is a one-to-many dictionary that maps keys to collections of values.

Zip

Zip creates an Enumerable of tuples, where the first element of the tuple is the element from the first sequence and the second element is the element from the second sequence.

int[] first = [1, 2, 3];
string[] second = ["a", "b", "c"];
//Returns [(1, "a"), (2, "b"), (3, "c")]
first.Zip(second); 

Skip & Take

var take3 = orders.Take(3);
var ne√t3 = orders.Skip(3).Take(3);

Element operations

//throws e√ception if element not found
var firstCustomer = customers.First(customer => customer.Id == 63);
var lastCustomer = customers.Last(customer => customer.Id == 63);
//returns default value if element not found. For refenrence types this is null!
var firstCustomer = customers.FirstOrDefault(customer => customer.Id == 63);
var lastCustomer = customers.LastOrDefault(customer => customer.Id == 63);
//You can specify the default return value with the 2nd parameter:
var firstCustomer = customers.FirstOrDefault(customer => customer.Id == 63, new Cutomer());
var lastCustomer = customers.LastOrDefault(customer => customer.Id == 63, new Customer());

Conversions

Order[] orders = Orders.Where(order => order.CustomerId == 66).ToArray();
List<Order> orders = Orders.Where(order => order.CustomerId == 66).ToList();
HashSet<Order> orders = Orders.Where(order => order.CustomerId == 66).ToHashSet();
Dictionary<int, string> customerDictionary
     = Customers.ToDictionary(customer => customer.Id, customer => customer.Name);

Enumerable class

//Create a range of numbers from 0 to 9
IEnumerable<int> range = Enumerable.Range(0, 10);
//Create a sequence of 12 "foo" strings
IEnumerable<string> foos = Enumerable.Repeat("foo", 12);
//Create an empty sequence of integers
IEnumerable<int> empty = Enumerable.Empty<int>();

Linq Execution

linq-execution #direction: right #spacing: 10 #gravity: .8 #arrowSize: 4 #title: linq-execution [Deferred|The operation isn't performed at the point in the code where the query is declared] [Immediate| The data source is read and the operation is performed once] [Streaming| Operations that desn't have to read all the source data before they yield element.] [Nonstreaming| Operations that must read all the source data before they can yie ld a result element] [LINQ Execution] - [Immediate] [LINQ Execution] - [Deferred] [Deferred] - [Streaming] [Deferred] - [Nonstreaming] Deferred The operation isn't performed at the point in the code where the query is declared Immediate The data source is read and the operation is performed once Streaming Operations that desn't have to read all the source data before they yield element. Nonstreaming Operations that must read all the source data before they can yie ld a result element LINQ Execution

Classification of standard query operators by manner of execution
Standard query operator Return type Immediate Deferred streaming Deferred nonstreaming
Aggregate TSource
All bool
Any bool
AsEnumerable IEnumerable<T>
Average Single numeric value
Cast IEnumerable<T>
Concat IEnumerable<T>
Contains bool
Count int
DefaultIfEmpty IEnumerable<T>
Distinct IEnumerable<T>
ElementAt TSource
ElementAtOrDefault TSource?
Empty IEnumerable<T>
E√cept IEnumerable<T>
First TSource
FirstOrDefault TSource?
GroupBy IEnumerable<T>
GroupJoin IEnumerable<T>
Intersect IEnumerable<T>
Join IEnumerable<T>
Last TSource
LastOrDefault TSource?
LongCount long
Ma√ Single numeric value, TSource, or TResult?
Min Single numeric value, TSource, or TResult?
OfType IEnumerable<T>
OrderBy IOrderedEnumerable<T>
OrderByDescending IOrderedEnumerable<T>
Range IEnumerable<T>
Repeat IEnumerable<T>
Reverse IEnumerable<T>
Select IEnumerable<T>
SelectMany IEnumerable<T>
SequenceEqual bool
Single TSource
SingleOrDefault TSource?
Skip IEnumerable<T>
SkipWhile IEnumerable<T>
Sum Single numeric value
Take IEnumerable<T>
TakeWhile IEnumerable<T>
ThenBy IOrderedEnumerable<T>
ThenByDescending IOrderedEnumerable<T>
ToArray TSource[] array
ToDictionary Dictionary<TKey, TValue>
ToList IList<T>
ToLookup ILookup<T>
Union IEnumerable<T>
Where IEnumerable<T>