LINQ
NamespaceSystem.Linq
CategoryQuerying collections
In UnitySorting high scores, filtering inventories, finding the closest enemy

LINQ

LINQ (Language Integrated Query) is a set of methods for asking questions about collections: "which items are weapons?", "sort enemies by distance", "what's the total value?". Each is one readable line instead of a hand-written loop. Add using System.Linq;.

A conveyor belt in a factory. Items go in one end. Where is a worker who throws out items that don't pass inspection. Select is a worker who repackages each item into something else. OrderBy sorts them. At the end, ToList() puts everything into a box for you. Nothing moves until someone at the end asks for the result.

Most-used methods

MethodDoesExample
Where(x => ...)Keep items that matchitems.Where(i => i.isWeapon)
Select(x => ...)Turn each item into something elseenemies.Select(e => e.name)
OrderBy / OrderByDescendingSort by a valuescores.OrderByDescending(s => s.points)
First() / FirstOrDefault()First item (throws / returns default if none)items.FirstOrDefault(i => i.id == id)
Any(x => ...)Does at least one match?enemies.Any(e => e.IsBoss)
All(x => ...)Do all match?switches.All(s => s.isOn)
Count(x => ...)How many match?items.Count(i => i.isKey)
Sum, Min, Max, AverageMath over valuesitems.Sum(i => i.weight)
Take(n) / Skip(n)Only the first n / all but the first nsorted.Take(10) (top 10)
Distinct()Remove duplicatestags.Distinct()
ToList() / ToArray()Run the query and store the resultsorted.Take(10).ToList()

Code Samples

Top 5 high scores

using System.Collections.Generic;
using System.Linq;

List<ScoreEntry> top5 = allScores
    .OrderByDescending(s => s.points)
    .Take(5)
    .ToList();

Inventory questions

bool hasKey        = inventory.Any(i => i.type == ItemType.Key);
float totalWeight  = inventory.Sum(i => i.weight);
var potions        = inventory.Where(i => i.type == ItemType.Potion).ToList();
string[] itemNames = inventory.Select(i => i.displayName).ToArray();

Closest enemy (the loop version is better in Update)

// LINQ: clear, fine for occasional use (e.g. when the player presses "lock on")
Enemy closest = enemies
    .OrderBy(e => (e.transform.position - transform.position).sqrMagnitude)
    .FirstOrDefault();

// Loop: no garbage, faster, better if it runs every frame
Enemy best = null;
float bestDist = float.MaxValue;
foreach (Enemy e in enemies)
{
    float d = (e.transform.position - transform.position).sqrMagnitude;
    if (d < bestDist) { bestDist = d; best = e; }
}

What happens at runtime

  1. Deferred execution: Where, Select and OrderBy don't do anything yet. They build a recipe. The work happens when you loop over it or call ToList(), First(), Count(), etc.
  2. If you loop over the same un-stored query twice, it runs twice. Store it with ToList() if you'll reuse it.
  3. Each LINQ call creates small objects (the query, the lambda, an enumerator), which is garbage. Harmless once, noticeable if done every frame on many objects.

Common Mistakes

See also