bitbonk
bitbonk

Reputation: 49599

Find first element of certain type in a list using LINQ

What would be the shortest notation to find the first item that is of a certain type in a list of elements using LINQ and C#.

Upvotes: 25

Views: 17478

Answers (5)

Ricardo Valente
Ricardo Valente

Reputation: 591

I recommend hugoware's answer, to avoid unnecessary iterations:

(string)source.FirstOrDefault(f => f is string)

But if you worry about micro optimizations, you could create your own extension method:

public static class ListExtensions
{
    public static T FirstOrDefault<T>(this IList source)
    {
        for (int i = 0; i < source.Count; i++)
        {
            if (source[i] is T)
                return (T)source[i];
        }
            
        return default;
    }
}

Benchmarks using a 100 objects lists where only the last one is a string (dotnet 7, BenchmarkDotNet):

[Benchmark]
public string OfType_First() => objects.OfType<string>().FirstOrDefault();

[Benchmark]
public string FirstOrDefault() => (string)objects.FirstOrDefault(f => f is string);

[Benchmark]
public string FirstOrDefault_T() => objects.FirstOrDefault<string>();
|           Method | Size |       Mean |    Error |    StdDev | Allocated |
|----------------- |----- |-----------:|---------:|----------:|----------:|
|     OfType_First |  100 | 1,229.0 ns | 57.86 ns | 157.41 ns |      96 B |
|   FirstOrDefault |  100 |   920.1 ns | 18.31 ns |  31.59 ns |      40 B |
| FirstOrDefault_T |  100 |   671.4 ns | 12.24 ns |  15.91 ns |         - |

// * Legends *
  Size      : Value of the 'Size' parameter
  Mean      : Arithmetic mean of all measurements
  Error     : Half of 99.9% confidence interval
  StdDev    : Standard deviation of all measurements
  Median    : Value separating the higher half of all measurements (50th percentile)
  Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
  1 ns      : 1 Nanosecond (0.000000001 sec)

Upvotes: 0

hugoware
hugoware

Reputation: 36397

You could just use the FirstOrDefault and pass in the delegate to use for the comparison.

object[] list = new object[] {
    4,
    "something",
    3,
    false,
    "other"
};

string first = list.FirstOrDefault(o => o is string); //something

Upvotes: 6

LukeH
LukeH

Reputation: 269278

var first = yourCollection.OfType<YourType>().First();

Note that the First method will throw an exception if there are no elements of type YourType. If you don't want that then you could use FirstOrDefault or Take(1) instead, depending on the behaviour you do want.

Upvotes: 39

jason
jason

Reputation: 241583

You want Enumerable.OfType:

list.OfType<MyType>().First();

Upvotes: 8

Akselsson
Akselsson

Reputation: 790

Use the OfType extension method:

public static T FindFirstOfType<T>(IEnumerable list){
 return list.OfType<T>().FirstOrDefault();
}

Upvotes: 15

Related Questions