LINQ
Prerequisites: Lambdas and delegates
LINQ (Language-Integrated Query) filters, sorts, groups, and transforms collections. Visual Basic supports it in two styles: query syntax, which reads like SQL, and method syntax with lambdas.
Query syntax
Module Program
Sub Main()
Dim numbers = {5, 3, 8, 1, 9, 2}
Dim bigOnes = From n In numbers
Where n > 3
Order By n Descending
Select n * 10
Console.WriteLine(String.Join(" ", bigOnes))
End Sub
End Module
90 80 50
Method syntax
Module Program
Sub Main()
Dim numbers = {5, 3, 8, 1, 9, 2}
Console.WriteLine(String.Join(" ", numbers.Where(Function(n) n Mod 2 = 0)))
Console.WriteLine(String.Join(" ", numbers.Select(Function(n) n * n)))
Console.WriteLine(String.Join(" ", numbers.OrderBy(Function(n) n).Take(3)))
Console.WriteLine($"{numbers.Count()} {numbers.Sum()} {numbers.Min()} {numbers.Max()} {numbers.Average():F2}")
Console.WriteLine(numbers.Any(Function(n) n > 8))
Console.WriteLine(numbers.All(Function(n) n > 0))
Console.WriteLine(numbers.First(Function(n) n > 5))
Console.WriteLine(numbers.FirstOrDefault(Function(n) n > 100))
End Sub
End Module
8 2
25 9 64 1 81 4
1 2 3
6 28 1 9 4.67
True
True
8
0
FirstOrDefault returns the type's default (0 here, Nothing for
objects) when nothing matches, while First throws.
Querying objects
Public Class Sale
Public Property Person As String
Public Property Region As String
Public Property Amount As Decimal
End Class
Module Program
Sub Main()
Dim sales As New List(Of Sale) From {
New Sale With {.Person = "Ada", .Region = "North", .Amount = 120D},
New Sale With {.Person = "Grace", .Region = "South", .Amount = 340D},
New Sale With {.Person = "Linus", .Region = "North", .Amount = 90D},
New Sale With {.Person = "Margaret", .Region = "South", .Amount = 210D}
}
Dim totals = From s In sales
Group By s.Region Into Total = Sum(s.Amount), Count()
Order By Total Descending
For Each t In totals
Console.WriteLine($"{t.Region}: {t.Total} from {t.Count} sales")
Next
Dim top = sales.OrderByDescending(Function(s) s.Amount).First()
Console.WriteLine($"Top seller: {top.Person}")
Dim names = From s In sales Where s.Amount > 100D Select s.Person
Console.WriteLine(String.Join(", ", names))
End Sub
End Module
South: 550 from 2 sales
North: 210 from 2 sales
Top seller: Grace
Ada, Grace, Margaret
VB's query syntax is richer than C#'s: Group By ... Into can compute
aggregates (Sum, Count, Average, Max) directly, and there are
Aggregate, Skip While, Take While, and Distinct clauses too.
Deferred execution
A query is a recipe: it runs when you enumerate it, and again every time you do:
Module Program
Sub Main()
Dim items As New List(Of Integer) From {1, 2, 3}
Dim evens = items.Where(Function(n) n Mod 2 = 0)
items.Add(4)
Console.WriteLine(String.Join(" ", evens))
Dim snapshot = items.Where(Function(n) n Mod 2 = 0).ToList()
items.Add(6)
Console.WriteLine(String.Join(" ", snapshot))
End Sub
End Module
2 4
2 4
Call ToList() or ToArray() to run a query once and keep the
results.
Practice
From the words {"apple", "Banana", "cherry", "avocado", "blueberry"},
list the words grouped by first letter (case-insensitive), with the
words in each group sorted.
Show solution
Module Program
Sub Main()
Dim words = {"apple", "Banana", "cherry", "avocado", "blueberry"}
Dim groups = From w In words
Order By w.ToLower()
Group By Letter = Char.ToLower(w(0)) Into Items = Group
Order By Letter
For Each g In groups
Console.WriteLine($"{g.Letter}: {String.Join(", ", g.Items)}")
Next
End Sub
End Module
a: apple, avocado
b: Banana, blueberry
c: cherry