== Resources

=== Documentation

* https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.find[List<T>.Find(Predicate<T>)]
* https://learn.microsoft.com/en-us/dotnet/api/system.array.find[Array.Find<T>(T[\], Predicate<T>)]
* https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable.immutablelist-1.find[ImmutableList<T>.Find(Predicate<T>)]
* https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.firstordefault[Enumerable.FirstOrDefault(Predicate<T>)]

=== Benchmarks

[options="header"]
|===
| Method                      | Runtime              | Categories       | Mean       | Standard Deviation    | Allocated
| ArrayFirstOrDefault         | .NET 8.0             | Array            |  10.515 μs | 0.1410 μs |      32 B
| ArrayFind                   | .NET 8.0             | Array            |   4.417 μs | 0.0729 μs |         -
|                             |                      |                  |            |           |
| ArrayFirstOrDefault         | .NET 9.0             | Array            |   2.262 μs | 0.0135 μs |         -
| ArrayFind                   | .NET 9.0             | Array            |   3.428 μs | 0.0206 μs |         -
|                             |                      |                  |            |           |
| ArrayFirstOrDefault         | .NET Framework 4.8.1 | Array            |  45.074 μs | 0.7517 μs |      32 B
| ArrayFind                   | .NET Framework 4.8.1 | Array            |  13.948 μs | 0.1496 μs |         -
|                             |                      |                  |            |           |
| ImmutableListFirstOrDefault | .NET 8.0             | ImmutableList&lt;T&gt; |  83.796 μs | 1.3199 μs |      72 B
| ImmutableListFind           | .NET 8.0             | ImmutableList&lt;T&gt; |  59.720 μs | 1.0723 μs |         -
|                             |                      |                  |            |           |
| ImmutableListFirstOrDefault | .NET 9.0             | ImmutableList&lt;T&gt; |  81.984 μs | 1.0886 μs |      72 B
| ImmutableListFind           | .NET 9.0             | ImmutableList&lt;T&gt; |  58.288 μs | 0.8079 μs |         -
|                             |                      |                  |            |           |
| ImmutableListFirstOrDefault | .NET Framework 4.8.1 | ImmutableList&lt;T&gt; | 446.893 μs | 9.8430 μs |      76 B
| ImmutableListFind           | .NET Framework 4.8.1 | ImmutableList&lt;T&gt; | 427.476 μs | 3.3371 μs |         -
|                             |                      |                  |            |           |           
| ListFirstOrDefault          | .NET 8.0             | List&lt;T&gt;          |  14.808 μs | 0.1723 μs |      40 B
| ListFind                    | .NET 8.0             | List&lt;T&gt;          |   6.040 μs | 0.1104 μs |         -
|                             |                      |                  |            |           |
| ListFirstOrDefault          | .NET 9.0             | List&lt;T&gt;          |   2.233 μs | 0.0154 μs |         -
| ListFind                    | .NET 9.0             | List&lt;T&gt;          |   4.458 μs | 0.0745 μs |         -
|                             |                      |                  |            |           |
| ListFirstOrDefault          | .NET Framework 4.8.1 | List&lt;T&gt;          |  57.290 μs | 1.0494 μs |      40 B
| ListFind                    | .NET Framework 4.8.1 | List&lt;T&gt;          |  18.476 μs | 0.0504 μs |         -
|===

==== Glossary

* https://en.wikipedia.org/wiki/Arithmetic_mean[Mean]
* https://en.wikipedia.org/wiki/Standard_deviation[Standard Deviation]
* https://en.wikipedia.org/wiki/Memory_management[Allocated]

The results were generated by running the following snippet with https://github.com/dotnet/BenchmarkDotNet[BenchmarkDotNet]:

[source,csharp]
----
// Explicitly cache the delegates to avoid allocations inside the benchmark.
private readonly static Func<int, bool> ConditionFunc = static x => x == 1;
private readonly static Predicate<int> ConditionPredicate = static x => x == 1;
private List<int> list;
private ImmutableList<int> immutableList;
private int[] array;
public const int N = 10_000;

[GlobalSetup]
public void GlobalSetup()
{
    list = Enumerable.Range(0, N).Select(x => N - x).ToList();
    immutableList = ImmutableList.CreateRange(list);
    array = list.ToArray();
}

[BenchmarkCategory("List<T>"), Benchmark(Baseline = true)]
public int ListFirstOrDefault() =>
    list.FirstOrDefault(ConditionFunc);

[BenchmarkCategory("List<T>"), Benchmark]
public int ListFind() =>
    list.Find(ConditionPredicate);

[BenchmarkCategory("ImmutableList<T>"), Benchmark(Baseline = true)]
public int ImmutableListFirstOrDefault() =>
    immutableList.FirstOrDefault(ConditionFunc);

[BenchmarkCategory("ImmutableList<T>"), Benchmark]
public int ImmutableListFind() =>
    immutableList.Find(ConditionPredicate);

[BenchmarkCategory("Array"), Benchmark(Baseline = true)]
public int ArrayFirstOrDefault() =>
    array.FirstOrDefault(ConditionFunc);

[BenchmarkCategory("Array"), Benchmark]
public int ArrayFind() =>
    Array.Find(array, ConditionPredicate);
----

Hardware configuration:

[source]
----
BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4317/23H2/2023Update/SunValley3)
11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 physical cores
  [Host]               : .NET Framework 4.8.1 (4.8.9277.0), X64 RyuJIT VectorSize=256
  .NET 8.0             : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
  .NET 9.0             : .NET 9.0.0 (9.0.24.47305), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
  .NET Framework 4.8.1 : .NET Framework 4.8.1 (4.8.9277.0), X64 RyuJIT VectorSize=256
----
