2

All

I have three collections:

{"Alex", "Anna"}
{19, 20}
{"A", "B"}

I want to project them all into one sequence of objects of type "Student" using LINQ and the following lambda or something:

(name, age, grade)=>new Student(name, age, grade)

Result should be two Student objects ("Alex", 19, "A") and ("Anna", 20, "B")

How can I do this?

Oleksandr Nechai
  • 1,811
  • 16
  • 27
  • 1
    How those sequences are defined? I mean their `Type`? Your question is unclear. – Rahul Singh Jan 13 '15 at 10:56
  • So far you have provided a requirement but no question. I'm going to assume the question is "how do I do this?". – Daniel Kelley Jan 13 '15 at 10:57
  • 1
    C# doesn't have sequences. Are you trying to convert F# code to C#? LINQ allows Zip-ing two enumerables but three is a different case – Panagiotis Kanavos Jan 13 '15 at 10:58
  • They are three simple enumerables, arrays or lists – Oleksandr Nechai Jan 13 '15 at 10:58
  • Wait. Why do you have list of three sequences in first place if you need them to be together? Why not have a single sequence `List` from the beginning itself? – Sriram Sakthivel Jan 13 '15 at 10:59
  • @SriramSakthivel notice the F#-like syntax. The sequences may come from various sources. Combining them in F# is easy. Elegantly doing the same in C# is non-trivial – Panagiotis Kanavos Jan 13 '15 at 11:00
  • If those sequences implement `IList` use a `for-loop`. That's simple and the most efficient approach. – Tim Schmelter Jan 13 '15 at 11:01
  • @DanielKelley the answers show that the question isn't trivial,even though the wording could be better. Converting an elegant F# statement to C# isn't easy and the answers show that. For example, how can you remove the double iteration inherent in the double-Zip solution? This isn't nitpicking - such statements are very common in data-processing scenarios with languages like F# and R. An elegant and *efficient* solution in C# is very useful – Panagiotis Kanavos Jan 13 '15 at 11:13
  • @PanagiotisKanavos Not one word of that comment addresses my comment. "Questions" with interesting problems don't by definition become immune from downvotes if they are asked poorly and show no effort by the asker. Hence downvotes. – Daniel Kelley Jan 13 '15 at 11:18
  • 1
    possible duplicate of [Merge multiple Lists into one List with LINQ](http://stackoverflow.com/questions/14639481/merge-multiple-lists-into-one-list-with-linq) – default Jan 13 '15 at 11:30

2 Answers2

5

You can combine two Zip to achieve this:

names.Zip(ages, (n,a) => new { name = n, age = a })
     .Zip(grades, (s,g) => new Student { Name = s.name, Age = s.age, Grade = g });
Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • 4
    I think your anonymous class makes for a more readable solution then my tuple. – Andrew Shepherd Jan 13 '15 at 11:03
  • The double-zip solution iterates twice over the first two sequences. For data-processing scenarios this is undesirable. I'll try to write a three-way Zip but I wonder if there are libraries out there that do this already. – Panagiotis Kanavos Jan 13 '15 at 11:15
  • 3
    @PanagiotisKanavos Actually, there is only one iteration. The first lambda and the second lambda are continually interleaved. See this dotnetfiddle for an example: https://dotnetfiddle.net/cRDQWM – Andrew Shepherd Jan 13 '15 at 11:27
  • 1
    @PanagiotisKanavos it seems it [has been done](http://stackoverflow.com/a/14639590/238902) – default Jan 13 '15 at 11:29
2

I'd use Zip

var names = new[] {"Alex", "Anna"};
var ages = new[] {19, 20}
var grades = new[] {"A", "B"}


var students = names.Zip(ages, (n, a) => Tuple.Create(n, a))
                    .Zip(grades, (t, g) => new Student(t.Item1, t.Item2, g));
Andrew Shepherd
  • 44,254
  • 30
  • 139
  • 205
  • 4
    I like the tuple, this is one of the rare cases where it's useful. – Tim Schmelter Jan 13 '15 at 11:02
  • The double-zip solution iterates twice over the first two sequences. For data-processing scenarios this is undesirable. I'll try to write a three-way Zip but I wonder if there are libraries out there that do this already – Panagiotis Kanavos Jan 13 '15 at 11:15
  • 2
    @PanagiotisKanavos - See my response to your same comment on Selman's answer. http://stackoverflow.com/a/27920582/25216 – Andrew Shepherd Jan 13 '15 at 11:28
  • 2
    So obvious in retrospective! The results are enumerables so the lambdas are always lazily evaluated. Enumerable never ceases to amaze me – Panagiotis Kanavos Jan 13 '15 at 11:35
  • @TimSchmelter - I got to use tuples again in another question. I find that their real power is that they override`Equals` and `GetHashCode` in a useful way. http://stackoverflow.com/questions/27953160/linq-select-distinct-set-and-retrive-different-column/27953448#27953448 – Andrew Shepherd Jan 14 '15 at 22:31
  • 1
    @AndrewShepherd: not a real advantage over their competitors anonymous types because they also provide that. The only advantage of tuples are that they can be processed in a different method. – Tim Schmelter Jan 14 '15 at 22:37
  • @TimSchmelter - OK, I just wrote more test code, and I see what you mean. I hadn't realised that anonymous types also override `Equals` and `GetHashCode`. – Andrew Shepherd Jan 14 '15 at 22:44
  • 1
    @AndrewShepherd: interesting is that the order matters, you can read about it here: http://blogs.msdn.com/b/ericlippert/archive/2012/01/30/anonymous-types-unify-within-an-assembly-part-two.aspx – Tim Schmelter Jan 14 '15 at 22:49