Rx: EnumerableEx.For() vs Enumerable.SelectMany()
Asked Answered
N

3

8

System.Interactive.dll includes a For() method with the following implementation:

IEnumerable<TResult> For<TSource, TResult>(
    IEnumerable<TSource> source,
    Func<TSource, IEnumerable<TResult>> resultSelector)
{
    return source.Select<TSource, IEnumerable<TResult>>(resultSelector).Concat<TResult>();
}

Am I missing something or is this equivalent to the existing Enumerable.SelectMany(), minus this?

IEnumerable<TResult> SelectMany<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, IEnumerable<TResult>> selector)
Newton answered 6/10, 2010 at 3:34 Comment(0)
U
2

Good question. They produce the same results but the internal implementations are quite different.

EnumerableEx.For would have been added to System.Interactive to maintain duality between IObservable and IEnumerables. Note that Observable.For and Observable.SelectMany are different:

IObservable<TResult> For<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, IObservable<TResult>> resultSelector)

vs.,

IObservable<TResult> SelectMany<TSource, TResult>(this IObservable<TSource> source, Func<TSource, IObservable<TResult>> selector)

Therefore you'd expect that EnumerableEx.For would have this signature, rather than the one it actually has:

IEnumerable<TResult> For<TSource, TResult>(**IObservable**<TSource> source, Func<TSource, IEnumerable<TResult>> resultSelector)

However, it obviously doesn't take an IObservable source. Perhaps it was meant to. I would ask your question in the Rx forums, to see if the Rx team has an answer.

Uphroe answered 6/10, 2010 at 21:34 Comment(1)
Asked on the Rx forums: social.msdn.microsoft.com/Forums/en-US/rx/thread/…Newton
K
0

They look like equivalent functionality to me. SelectMany is an extension method on an IEnumerable and .For is written as a static method on EnumerableEx, so they are called differently.

    foreach(var s in list.SelectMany(Filter))
    {
        // ...
    }

    foreach (var s in EnumerableEx.For(list, Filter))
    {
        // ...
    }

I'm sure there are specific reasons for using each one.

Kerek answered 6/10, 2010 at 17:45 Comment(0)
B
0

My guess is that SelectMany traverses everything dynamically, whereas Concat (in For) traverses all of its outer IEnumerable elements before starting to register with and iterate over them.

In other words, Concat works with a fixed set of IEnumerable even if it receives them as an IEnumerable. Therefore, in For, the the entire set of IEnumerable is created before even returning the first TResult. In SelectMany, you receive a TResult instantly.

Bradshaw answered 5/2, 2011 at 15:27 Comment(2)
Since all the operators involved (SelectMany, Select and Concat) are deferred, I'm not sure any difference in implementation would translate to a different end behavior. Some testing with side effects at various points in each operator's selector seems to always yield the same deferred result.Newton
In concat, you already know how many IEnumerable you need to work with, while in SelectMany, its amount depends on how many elements arrive from the source. For constant sized input sources, both should produce the sameBradshaw

© 2022 - 2024 — McMap. All rights reserved.