C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
Left, right: To the left, we have arguments. The "x" is just a name—we can use any valid name. The result is on the right.
Often: We pass lambda expressions as arguments, for sorting or for searching. We use them in queries.
C# program that uses lambda, List
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<int> elements = new List<int>() { 10, 20, 31, 40 };
// ... Find index of first odd element.
int oddIndex = elements.FindIndex(x => x % 2 != 0);
Console.WriteLine(oddIndex);
}
}
Output
2
Lambda details:
x The argument name.
=> Separates argument list from result expression.
x % 2 !=0 Returns true if x is not even.
Part 1: We assign a lambda to func1. This lambda receives an int, and returns 1 plus that int value.
Part 2: The lambda here receives an int, and returns 1 plus that int also (just like func1).
Part 3: This lambda is another syntax for the same lambda—it has the same result as the previous 2 Func objects.
Part 4: We see a more verbose syntax here—we specify the return keyword, and the argument type of the lambda.
ReturnC# program that uses lambda, Func
using System;
class Program
{
static void Main()
{
// Part 1: use implicitly-typed lambda expression.
// ... Assign it to a Func instance.
Func<int, int> func1 = x => x + 1;
Console.WriteLine("FUNC1: {0}", func1.Invoke(200));
// Part 2: use lambda expression with statement body.
Func<int, int> func2 = x => { return x + 1; };
Console.WriteLine("FUNC2: {0}", func2.Invoke(200));
// Part 3: use formal parameters with expression body.
Func<int, int> func3 = (int x) => x + 1;
Console.WriteLine("FUNC3: {0}", func3.Invoke(200));
// Part 4: use parameters with a statement body.
Func<int, int> func4 = (int x) => { return x + 1; };
Console.WriteLine("FUNC4: {0}", func4.Invoke(200));
}
}
Output
FUNC1: 201
FUNC2: 201
FUNC3: 201
FUNC4: 201
Func signatures:
Func<TResult> Has one result value, no parameter.
Func<T, TResult> Has one result value, one parameter.
Func<T1, T2, TResult> Has one result value, two parameters.
Func<T1, T2, T3, TResult> ....
C# program that uses lambda with 2 arguments, Func
using System;
class Program
{
static void Main()
{
// Use multiple parameters.
Func<int, int, int> func = (x, y) => x * y;
// ... No need to call Invoke(), just call lambda directly.
Console.WriteLine("RESULT: {0}", func(20, 2));
}
}
Output
RESULT: 40
C# program that uses Action lambda
using System;
class Program
{
static void Main()
{
// Use no parameters in a lambda expression.
// ... This is an Action instance.
Action value = () => Console.WriteLine("Hi, friend");
value.Invoke();
}
}
Output
Hi, friend
Part A: This delegate (an anonymous function) has 1 argument of type int. It returns an int as well.
Part B: The delegate here has no arguments. It just returns an int. It is assigned to a Func object.
C# program that uses delegate keyword, Func
using System;
class Program
{
static void Main()
{
// Part A: use delegate method expression.
Func<int, int> test1 = delegate (int x) { return x + 1; };
Console.WriteLine(test1.Invoke(10));
// Part B: use delegate expression with no parameter list.
Func<int> test2 = delegate { return 1 + 1; };
Console.WriteLine(test2.Invoke());
}
}
Output
11
2
Invoke: In this program, the Invoke method is used to show that the Predicate works as expected.
C# program that uses Predicate
using System;
class Program
{
static void Main()
{
Predicate<int> predicate = value => value == 5;
Console.WriteLine(predicate.Invoke(4));
Console.WriteLine(predicate.Invoke(5));
}
}
Output
False
True
Here: We create a lookup table of 3 functions, and call them based on an index.
Results: The output shows that the offsets 100,200 and 300 are added in an alternating way to the for-iteration value.
C# program that shows array of lambda Funcs
using System;
class Program
{
static void Main()
{
// Create an array of lambdas.
var lookup = new Func<int, int>[]
{
a => a + 100,
a => a + 200,
a => a + 300
};
// Call the lambdas in the lookup table and print the results.
for (int i = 0; i < 10; i++)
{
int result = lookup[i % 3](i);
Console.WriteLine(result);
}
}
}
Output
100
201
302
103
204
305
106
207
308
109
C# program that uses lambda syntax, method
class Program
{
static int TreeBranches(int branches, int trunks) => (branches * trunks);
static void Main()
{
// Call the expression-bodied method.
System.Console.WriteLine(TreeBranches(10, 2));
}
}
Output
20
Important: Look at the two parts of the lambda separated by the => syntax. The variable name should be present on both sides.
C# program that shows possible lambda error
using System;
class Program
{
static void Main()
{
var array = new int[] { 10, 20, 30 };
var result = Array.Find(array, element => 20);
}
}
Output
Error CS1662
Cannot convert lambda expression to intended delegate type because some of the return types
in the block are not implicitly convertible to the delegate return type
Error CS0029
Cannot implicitly convert type 'int' to 'bool'
Tip: We changed the right-hand side of the lambda to have an equality expression, so it now evaluates to a bool correctly.
C# program that shows correct lambda expression
using System;
class Program
{
static void Main()
{
var array = new int[] { 10, 20, 30 };
var result = Array.Find(array, element => element == 20);
Console.WriteLine(result);
}
}
Output
20
Version 1: This version of the code uses a lambda expression. It passes the lambda to the Count() method.
Version 2: Here we use a delegate reference instead of a directly-specified lambda expression as the argument to Count.
Result: We found no differences. The lambda expression performed the same as the explicit Func instance.
C# program that benchmarks delegate, lambda
using System;
using System.Diagnostics;
using System.Linq;
class Program
{
const int _max = 10000000;
static void Main()
{
int[] array = { 1 };
Func<int, bool> delegateVersion = delegate (int argument)
{
return argument == 1;
};
// Version 1: use lambda expression for Count.
var s1 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
if (array.Count(element => element == 1) == 0)
{
return;
}
}
s1.Stop();
// Version 2: use delegate for Count.
var s2 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
if (array.Count(delegateVersion) == 0)
{
return;
}
}
s2.Stop();
Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /
_max).ToString("0.00 ns"));
Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /
_max).ToString("0.00 ns"));
}
}
Output
25.85 ns lambda expression
25.72 ns delegate
And: We may need to reuse the lambda many times. We can store the lambda in a variable like a Comparison, and reuse it.
Version 1: In this version of the code, we call a lambda 3 times, but specify it as an argument expression 3 times.
Version 2: Here we cache the lambda expression in a local variable. So only 1 lambda is used.
Result: Using a cached lambda in repeat invocations is faster. Consider storing lambdas as static fields or local variables.
C# program that benchmarks lambda cache
using System;
using System.Diagnostics;
class Program
{
const int _max = 1000000;
static void Main()
{
int[] values = { 0, 10 };
// Version 1: use lambda directly in each Array.Sort call.
var s1 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
Array.Sort(values, (a, b) => (b.CompareTo(a)));
Array.Sort(values, (a, b) => (b.CompareTo(a)));
Array.Sort(values, (a, b) => (b.CompareTo(a)));
}
s1.Stop();
// Version 2: store lambda as local, then reuse it for each Array.Sort call.
var s2 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
Comparison<int> temp = (a, b) => (b.CompareTo(a));
Array.Sort(values, temp);
Array.Sort(values, temp);
Array.Sort(values, temp);
}
s2.Stop();
Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /
_max).ToString("0.00 ns"));
Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /
_max).ToString("0.00 ns"));
}
}
Output
141.58 ns Array.Sort, 3 separate lambdas
111.62 ns Array.Sort, 1 cached lambda
Performance: Using methods such as List.Sort or Array.Sort (with a Comparison) is often faster than using LINQ to sort on a property.
Quote: Higher-order procedures can serve as powerful abstraction mechanisms, vastly increasing the expressive power of our language (Structure and Interpretation of Computer Programs).
Tip: We can find more detail on this topic using the precise technical terminology on page 314 of this book.