Dmitry Petrov
Dmitry Petrov

Reputation: 1547

C# LINQ: remove null values from an array and return as not nullable

I'm converting nullable array to unnullable. This is my current code with two function calls:

myarray.Where(e => e.HasValue).Select(e => e.Value)

It looks like a very basic operation. Is it possible to do that in one call?

Upvotes: 9

Views: 12958

Answers (6)

Ilya Chernomordik
Ilya Chernomordik

Reputation: 30185

While .OfType<> solution works, the intent is not quite clear there, I suggest this solution that is pretty much the same that the solution in the question, but it allows compiler and e.g. R# to be sure in the output type and not have a warning for a possible null reference exception (for e.g. nullable reference types in C# 8).

myarray
  .Where(e => e != null)
  .Select(e => e ?? new Exception("Unexpected null value"))

This seems like a bit overkill, and can be fixed with e.g. "e!", but it's a bit more secure against future errors (if e.g. where clause is modified by mistake)

Upvotes: -1

Frank Bryce
Frank Bryce

Reputation: 8446

myarray.OfType<int>();

This works because nullable types box to their underlying types if they are not null, but don't if they are null.

EDIT: The only thing I'll point out is that the semantics of the one-liner I made are slightly different than yours. It could be that you'd want yours instead of mine. Your code: "grab all nullable objects which have a value". My code: "grab all types which can successfully be cast to int"

Upvotes: 19

Matthew Whited
Matthew Whited

Reputation: 22433

try using .OfType(...)

Example...

myarray.OfType<int>()

... this worked for me ...

var d = new int?[] { 1, 2, 3, 4, 5, null, null, 6, 7, 8, 9, null };
Console.WriteLine(d.Count()); // 12
Console.WriteLine(d.OfType<int>().Count()); //9

Upvotes: 4

fahadash
fahadash

Reputation: 3281

Your expression is as pretty as it can get, and thanks to how the Enumerables are looped through, your collection won't technically be visited twice in two separate loops.

If you still want to do it in a single expression, here is one of the many ugly ways.

myarray.Aggregate(Enumerable.Empty<YourElementType>(), (prev, next) => next.HasValue? prev.Concat(new [] { next }) : prev);

The above should never be used and it is only for demonstration purposes. I would use what you wrote in your question, yours is prettier.

Upvotes: 0

konkked
konkked

Reputation: 3231

You can always make your own extensions but that only makes your code seem more succinct, think that your implementation is the most succinct and clear you can get to be honest

public static IEnumerable<T> GetNonNullValues<T>(this IEnumerable<Nullable<T>> items) where T: struct
{
    return items.Where(a=>a.HasValue).Select(a=>a.Value);
}

Upvotes: 10

Jorge Rojas
Jorge Rojas

Reputation: 485

Try this:

myarray.Where(e => e.HasValue).Select(e => e.GetValueOrDefault()))

Upvotes: 1

Related Questions