Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spread tuples: [(x, x), (x, x), …] → [x, x, x, x, …] #939

Open
atifaziz opened this issue Jan 21, 2023 · 7 comments
Open

Spread tuples: [(x, x), (x, x), …] → [x, x, x, x, …] #939

atifaziz opened this issue Jan 21, 2023 · 7 comments

Comments

@atifaziz
Copy link
Member

atifaziz commented Jan 21, 2023

I propose to add a new operator that takes a sequence of tuples and spreads the elements of each tuple into the resulting sequence:

public static IEnumerable<T> Spread<T>(this IEnumerable<(T, T)> source)
{
    foreach (var (a, b) in source)
    {
        yield return a;
        yield return b;
    }
}

Additional overloads can be supplied for remaining multary tuple types.

Example:

using MoreLinq;

var xs =
    Enumerable.Range(1, 10)
              .Zip(MoreEnumerable.Return(0).Repeat())
           // ...above same as...
           // .Select(x => (x, 0))
              .Spread();

foreach (var x in xs)
    Console.WriteLine(x);

Outputs:

1
0
2
0
3
0
4
0
5
0
6
0
7
0
8
0
9
0
10
0

This would be more generally usable than what's proposed in #695.

@viceroypenguin
Copy link
Contributor

I would argue this is a fancier more opinionated version of Unfold, so I'd rather see Unfold be updated to support this type of behavior. Suggestions:
a) an overload that takes IEnumerable<> and effectively does source.SelectMany(x => Unfold(x))
b) an overload that takes ValueTuple and shortcuts the other parameters
c) both of the above?

@atifaziz
Copy link
Member Author

@viceroypenguin Do you mean Unfold that's a sequence generator? I guess I'm not seeing how the above is a fancier version of that. Could you expand/clarify?

@viceroypenguin
Copy link
Contributor

Sure, what you're describing here is basically sequence generation for a single ValueTuple (i.e. (t, t) => [t, t]), and a Flatten operation on the sequence of sequences. In effect, Spread(source) => source.SelectMany(x => new { x.Item1, x.Item2, }).

Reversing operation: IEnumerable<(T, T)> Unspread(IEnumerable<T> source) => source.Batch(2).Fold((x, y) => (x, y));

@atifaziz
Copy link
Member Author

Ah, you mean a generator for inner sequence? So you're saying (a) is the more general version of (b)? Do you mean the below?

public static IEnumerable<U> Spread<T, U>(this IEnumerable<T> source, Func<T, (U, U)> selector)
{
    foreach (var item in source)
    {
        var (a, b) = selector(item);
        yield return a;
        yield return b;
    }
}

@viceroypenguin
Copy link
Contributor

a) and b) are orthogonal to each other. Unfold as an operator works on an item right now.

a) Unfold as an operator on IEnumerable<T> should be: source.SelectMany(x => Unfold(x, ...));
b) I would argue that expanding a ValueTuple to an IEnumerable<T> is effectively an Unfold operation, just with specific opinionated semantics on what it means to Unfold a ValueTuple
c) would be the combination of both, i.e. the cartesian of both above ideas applied to Unfold.

This is just my argument, feel free to ignore if I'm wrong. :)

@declard
Copy link

declard commented Mar 28, 2023

That looks like

public static IEnumerable<T> AsEnumerable<T>(this (T Left, T Right) pair)
{
    yield return pair.Left;
    yield return pair.Right;
}

@atifaziz
Copy link
Member Author

@declard Not quite. That would be (x, x) → [x, x] whereas this is, as in the title, [(x, x), (x, x), …] → [x, x, x, x, …].

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants