-1

I want to get the following sequence:

enter image description here

Is it possible to use one SelectMany to get such a sequence?

Minimal Working Example

static void Main()
{
    var x = Enumerable.Range(1, 7).Where(n => n % 2 == 1);
    var y = Enumerable.Range(1, 7).Where(n => n % 2 == 0);
    var z = x.SelectMany(m => y, (m, n) => new int[] { m, n }).SelectMany(o => o);
    foreach (int n in z)
        Console.Write($"{n},");
    Console.WriteLine("\b.");
}
Second Person Shooter
  • 14,188
  • 21
  • 90
  • 165
  • This code will produce your desired result. Why do you want to have only one `SelectMany`? – Salah Akbari Feb 01 '18 at 14:47
  • Your code is fairly unreadable as it is (I can't for the life of me work out what sequence you are generating). I would imagine if you do cram it into a one liner then it will become even harder to understand what it is doing... – Chris Feb 01 '18 at 14:48
  • Can you clarify what you mean by "the same result"? You look like you are creating a cartesian product of two sets and then flattening them into a single string. Do you actually want the m,n pairs or do you want the string? – Chris Feb 01 '18 at 15:00
  • @ArtificialStupidity: No need to be snippy. Getting a cartesian product of two sets of numbers is a much more common thing to want to do than to then flatten that set into a single list of integers. It also wasn't clear if printing to console was the result you wanted or whether generating z was the end result. I'm assuming z (which in the spirit of being snippy I will note is not an array of numbers) and have answered accordingly. – Chris Feb 01 '18 at 15:09

3 Answers3

1

You can use a Tuple:

var z = x.SelectMany(m => y, (m, n) => new { m, n }).Select(k => Tuple.Create(k.m, k.n));

Or even simpler with new C# 7.0 feature value tuple:

var z = x.SelectMany(m => y, (m, n) => new { m, n }).Select(k => (k.m, k.n));
Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
  • Will z not then be an IEnumerable of Tuples rather than an IEnumerable of ints as desired? Or is there more magic to tuples than I am aware of? – Chris Feb 01 '18 at 15:17
1

What you are doing is a cartesian product and then flattening it. It can be done quite nicely in a few other ways:

var z = from m in x
from n in y
from t in new []{m,n}
select t;

Which is probably the nicest looking

var z = x.Join(y, _=>1, _=>1, (m,n)=>new int[] { m, n }).SelectMany(o => o);

This is closer to your original but substitutes your first SelectMany with a join. The key selectors are both _=>1 because you want the cartesian product which this will give you.

Chris
  • 27,210
  • 6
  • 71
  • 92
  • 1
    I think this snippy answer conforms to my requirement "single `SelectMany`". :-) – Second Person Shooter Feb 01 '18 at 15:18
  • 1
    @ArtificialStupidity: I've just come across some comments from Eric Lippert on https://stackoverflow.com/a/4073724/338068 which suggests that SelectMany is much better to use than Join for this sort of thing which means that probably performance-wise my suggestions are inferior to your original code. Though of course it is quite possible that performance isn't something you are worried about if your data sets aren't that big (I'm assuming the question here is a trimmed down version of what you are actually doing with real data). – Chris Feb 01 '18 at 15:41
1

Despite your requires, for the sake of code clearness I suggest you just to use nested loops, e.g.

IEnumerable<int> DummySequence(int n)
{
    var odd = Enumerable.Range(1, n).Where(x => x % 2 == 1);
    var even = Enumerable.Range(1, n).Where(x => x % 2 == 0).ToArray();

    foreach (var oddNumber in odd)
    {
        foreach (var evenNumber in even)
        {
            yield return oddNumber;
            yield return evenNumber;
        }
    }
}
rattrapper
  • 431
  • 2
  • 5
  • 17