Reputation: 16878
Let's assume that there is some class:
public class SomeClass
{
public string A;
public int B;
public double C;
}
and we have a collection of it:
var list = new List<SomeClass>()
{
new SomeClass() { A = "A", B = 2, C = 4.0 },
new SomeClass() { A = "B", B = 6, C = 8.0 }
};
How can we write in the most efficient way the transform of this collection into three arrays (or list of arrays) of values of A
, B
and C
respectively? In this case it would be:
var Ar = new[] { "A", "B" };
var Br = new[] { 2, 6 };
var Cr = new[] { 4.0, 8.0 };
So far I have working LINQ query:
var lists = list.SelectMany(c => new object[] { c.A, c.B, c.C })
.Select((v, i) => new { Index = i, Object = v})
.GroupBy(g => g.Index % 3, g => g.Object, (k,v) => v.ToArray())
.ToList();
but I wonder if I'm not missing something obvious and if there is possibility to do it clever, for example without the need for creating temporary subcollections within SelectMany
.
Edit: my question is rather from theoretical point of view - if it can be done in single LINQ query (for example as a part of another, more complex single query).
Upvotes: 1
Views: 276
Reputation: 125620
Why don't you do this the simplest possible way? I think that 3 separated queries should be more efficient then SelectMany
+GroupBy
solution:
var Ar = list.Select(x => x.A).ToList();
var Br = list.Select(x => x.B).ToList();
var Cr = list.Select(x => x.C).ToList();
It requires only 3 iterations over list
collection. With GroupBy
you have only one iteration but the source collection is 3 times longer then list
, so there is no difference (because of SelectMany
) with additional GetHashCode
calls to make the grouping.
Update
Single line version of the same approach:
var items = new [] {
list.Select(x => x.A).ToList(),
list.Select(x => x.B).ToList(),
list.Select(x => x.C).ToList()
}
Update 2
If you don't want to use SelectMany
, you can use Concat
instead. However, it would require change in GroupBy
as well:
var lists = list.Select(c => c.A)
.Concat(list.Select(c => c.B))
.Concat(list.Select(c => c.C))
.Select((v, i) => new { Index = i, Object = v})
.GroupBy(g => g.Index / list.Count, g => g.Object, (k,v) => v.ToArray())
.ToList();
Upvotes: 4