Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to select two values into same IEnumerable using LINQ in C#?

Tags:

c#

linq

I have a class that has two integers in it, for example A and B:

public class MyClass {
   public int A { get; set; }
   public int B { get; set; }
   ...other stuff...
}

I have a MyCollection of type ObservableCollection<MyClass> in code, and have a need to get an IEnumerable<int> of ALL the values -- both A's and B's -- together in one list.

I have figured out how to do it with quite verbose code (significantly simplified to be only one level below for example purposes, but actually 3 levels of "from" calls and selecting values from within nested lists):

IEnumerable<int> intsA=
    (from x in MyCollection
            select x.A);
IEnumerable<int> intsB =
    (from x in MyCollection
            select x.B);
IEnumerable<int> allInts = intsA.Concat(intsB);

It seems like there should be a way to select both variables at the same time into the same IEnumerable<int>. Obviously below doesn't work, but I'd love something like

IEnumerable<int> allInts = (from x in MyCollection select x.A, x.B);

Does something like this exist that is more elegant than what I have above?

I found how to select multiple values into an anonymous type here, but that doesn't make it into the same IEnumerable and still requires more code/processing to get the items out.

(BTW, using .NET 4.5.1, if that makes a difference.) Thanks!

like image 351
Meredith Avatar asked Mar 06 '15 21:03

Meredith


People also ask

Can LINQ be used on IEnumerable?

All LINQ methods are extension methods to the IEnumerable<T> interface. That means that you can call any LINQ method on any object that implements IEnumerable<T> . You can even create your own classes that implement IEnumerable<T> , and those classes will instantly "inherit" all LINQ functionality!

How do you select two columns in LINQ?

Select(x => new { x. EMAIL, x.ID }); AFAIK, the declarative LINQ syntax is converted to a method call chain similar to this when it is compiled. If you want the entire object, then you just have to omit the call to Select() , i.e.

How does select work in LINQ?

LINQ Select operator is used to return an IEnumerable collection of items, including the data performed on the transformation of the method. By using Select Operator, we can shape the data as per our needs. In it, we can use two syntax types; let's see each method working flow.

Why does LINQ return IEnumerable?

LINQ queries return a lazily evaluated IEnumerable<T> . The query is performed upon enumeration. Even if your source IEnumerable<T> had millions of records the above query would be instantaneous. Edit: Think of LINQ queries as creating a pipeline for your result rather than imperatively creating the result.


2 Answers

You could use SelectMany:

var result = source.SelectMany(x => new[] { x.A, x.B });

But because you'd allocate a new array for each object, I don't know how performance it will be (or maybe you don't care about it that much).

You could declare GetIntValues on your type which would return IEnumerable<int>:

public class MyClass {
   public int A { get; set; }
   public int B { get; set; }
   ...other stuff...

   public IEnumerable<int> GetIntValues()
   {
       yield return A;
       yield return B;
   }
}

And use it like this:

var result = source.SelectMany(x => x.GetIntValues());

But there is still an additional allocation for each element.

like image 68
MarcinJuraszek Avatar answered Sep 30 '22 05:09

MarcinJuraszek


That's pretty easy indeed:

IEnumerable<int> allInts = MyCollection.Select(i => i.A)
                                       .Concat(MyCollection.Select(i => i.B));

It's equivalent to what you wrote, but less verbose. It's using the lambda syntax instead of query comprehension syntax.

Use it if you want to avoid additional allocations. If you don't care about GC pressure, Marcin's solution is even shorter. Also, this outputs the elements in a different order than his solution.

like image 34
Lucas Trzesniewski Avatar answered Sep 30 '22 04:09

Lucas Trzesniewski