-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Consider adding more LINQ operators from Ix.NET #19522
Comments
+1 |
Related: |
Also relevant: https://github.com/morelinq/morelinq. @bartdesmet Nice proposal. I have a few comments, though:
IEnumerable<T> PrependMany<T>(this IEnumerable<T> source, params IEnumerable<T> prependees)
{
}
var onetwothree = Enumerable.Range(3, 1).PrependMany(1, 2); the compiler can cache the
|
I would expect them to return a single value (for example, MoreLinq's version does that). But if it's going to return a sequence, a list does make sense to me, since it can't really be lazy (though I would prefer Should it return a sequence containing all the values with the minimum/maximum key? Not sure. I think getting just a single value is the common case, and returning a sequence would make that common case more complex and also less efficient. On the other hand, knowing if there's a tie (and what values are tied) sounds useful too. Maybe both versions of the method should exist? Though in that case I'm not sure about naming (maybe |
I'm neither firmly for or against most of these, but a MinBy or MaxBy that returns more than one value is horrible, at least under that name. If you've more than one minima or maxima you either need more information that just the value (which that doesn't seem to offer to give) or you need to rethink your comparison criteria. |
@JonHanna When you add a selector it becomes feasible that multiple elements may be mapped to the same maxima. For example, if you wanted to find the oldest people in a struct Person { string Name; int Age; }
var people = new List<Person>
{
new Person { Name = "John", Age = 25 },
new Person { Name = "Tommy", Age = 80 },
new Person { Name = "Mary", Age = 80 }
};
var oldest = people.MaxBy(p => p.Age); If we took away the selector then returning an IEnumerable wouldn't make sense. That said, it might still be confusing/inconvenient that |
Oh, I get that it's possible to have more than one, but I don't think "MaxBy" is a good match for that, and often nor is just the value; one would often want to know indices too. |
I'll refrain from debating names here and provide some clarifications on the semantic decisions we made in Ix. (See Wadler's law.)
These observations / discussions lead me to conclude both cases (return a list a la Mathematica or a single element a la Scala) have a use. Also, getting the index is easy by composition with the overload of The choice of With regards to |
@bartdesmet Regarding List<List<T>> listOfLists = ...
T[] flat = listOfLists.SelectMany(l => l).ToArray(); are currently very hard to optimize because we do not know With |
I'd expect |
What's the status of this issue? It's still labeled IMO
|
That seems unnecessary since the return value doesn't need the type of the sequence before applying the selector. Just do |
It's true that |
Not anymore, see dotnet/corefx#2401. |
@svick nice! |
This would be great! Just as long as it is not called Regarding |
LINQ is all about productivity. Why not make a productive library even more productive? |
…reRT. (#14119) * Moving parts of `System.MathF` to be shared with CoreRT. * Moving parts of `System.Math` to be shared with CoreRT. * Updating the new 'Round' named intrinsic to map to the legacy 'Round' intrinsic. * Adding back the case statement for CORINFO_INTRINSIC_Round, since it is required for Desktop compat. Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
…reRT. (#14119) * Moving parts of `System.MathF` to be shared with CoreRT. * Moving parts of `System.Math` to be shared with CoreRT. * Updating the new 'Round' named intrinsic to map to the legacy 'Round' intrinsic. * Adding back the case statement for CORINFO_INTRINSIC_Round, since it is required for Desktop compat. Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
…reRT. (#14119) * Moving parts of `System.MathF` to be shared with CoreRT. * Moving parts of `System.Math` to be shared with CoreRT. * Updating the new 'Round' named intrinsic to map to the legacy 'Round' intrinsic. * Adding back the case statement for CORINFO_INTRINSIC_Round, since it is required for Desktop compat. Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
…reRT. (#14119) * Moving parts of `System.MathF` to be shared with CoreRT. * Moving parts of `System.Math` to be shared with CoreRT. * Updating the new 'Round' named intrinsic to map to the legacy 'Round' intrinsic. * Adding back the case statement for CORINFO_INTRINSIC_Round, since it is required for Desktop compat. Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
So nice suggestion! I want to use Ix.NET methods without Introducing Library via nuget. But it is so hard to introduce all Ix.Net methods at the same time to dotnet core.How about introduce and implement them individually? In this issue, we discuss about |
Why? |
https://github.com/dotnet/corefx/issues/14119#issuecomment-459973238 Because I want to use Ix.NET methods as language builtin Collection extension methods. I think, there is so big difference between
Many C#er study and can use LINQ to Objects (language builtin Collection extension methods). About LINQ to Objects, code reading, code review and communication are so easy because many people can use them. There are so many useful methods in Ix.NET. They make so big productivity. If Ix.NET methods are added in .NET core in the future, I think that many C#er will be able to use them. And code reading, code review and communication about them will become so easy. I think this introduce more productivity for C#er and C# community. Some people say that "You can create your own Collection extension methods". Many people create their own Collection extension methods individually. Sometime they are so useful, but sometime they are confused. Because they are not same implementation and specification. If C#(.NET Core) provides Ix.NET methods as language builtin methods, we can use as common implementation and specification methods. It is so useful and clear. Because I want to use Ix.NET methods as language builtin Collection extension methods. And I want to make many C#er know and can use Ix.NET methods. |
Thanks. I read all of those as, paraphrasing: "because I don't want to use another library". To me that's not a good enough reason to add such methods. The core frameworks simply cannot scale to add every possible extension method someone might want. For the .NET ecosystem to thrive, developers need to be comfortable using libraries from NuGet and the broader ecosystem. |
Thank you!
Yes! I understand and agree above.
I'm so sorry. My main suggestion and opiniton are that "I want to make many C#er can use Ix.NET methods." But I understand next important point at the same time.
By the way, Ix.NET So I submited new issue So I will not introduce all Ix.NET methods. But I will introduce methods that they are useful and need for .NET core from Ix.NET. |
I'd like to question the premise here. In Ix there is an existing popular library, available from NuGet, for free, that already enables any developer using .NET to get this functionality. What's the benefit of copying that functionality into Enumerable? I would much rather spend such efforts removing whatever roadblocks exist for folks to partake in the NuGet ecosystem. |
I'm totally for growing the ecosystem and ironing out any wrinkles that may hinder adoption of libraries through NuGet. One of the motivating issues for opening this was the conflict introduced by TakeLast and SkipLast in Ix where the same extension method ended up being provided in .NET, thus having to add #if in Ix to create different build flavors to resolve the ambiguity for users of those operators (while keeping downlevel support). This is the main drawback of multiple libraries providing the same extension methods and may be a topic to consider in the design of "extension everything". From the list above, the one inconsistency I see in System.Linq is the lack of a comparer on Min and Max, while other operators do provide a customization for comparers. All other proposals do not intersect with existing operators and can be punted to Ix. As for Ix, given the recent work on System.Linq.Async over there, I think it's totally fair to continue going down the road of contributing such libraries through NuGet and focus on discoverability. |
Related to #27687 |
As already mentioned adding more methods to System.Linq comes at a cost, so we would need to see strong evidence for the utility of any new method on a case by case basis. As it stands this issue is more of a wish list of assorted LINQ methods, making it more difficult to evaluate during API review. I would recommend closing it and creating separate issues for each proposal, so that we can have a more focused debate. A few thoughts on the individual proposals:
|
https://github.com/dotnet/corefx/issues/13842 introduces
TakeLast
andSkipLast
which existed in Ix.NET (System.Interactive
, which is part of the Reactive Extensions project) for a long time. This may be a good time to review other operators we got in Ix.NET and see whether they're worth adding to .NET proper.I'm pasting a short selection (using the Ix names) below:
Min and Max with IComparer
No overloads of these operators exist with an
IComparer<TSource>
. The existing overload usesComparer<TSource>.Default
to get the comparer. It seems an omission that we don't provide an option to pass in a custom comparer.MinBy and MaxBy to select element(s) with lowest/highest key value
Similar to
MinimalBy
andMaximalBy
in Mathematica. The current overloads with aFunc<TSource, TResult>
are merely shortcuts forxs.Select(f).Max()
rather than providing a means to get the list of values that have the lowest projected value (e.g. the list of people with the lowest value forAge
).Concat (or Flatten or Unwrap)
Just like
Task<Task<T>>
can be unwrapped intoTask<T>
orAggregateException
can be flattened. Obviously, this is just a macro forxss.SelectMany(xs => xs)
, but possibly more descriptive and having better performance.StartWith (Prepend with multiple values)
I noticed we've added
Prepend
. Ix providesStartWith
which is basically the same but takes aparams
array with elements to prepend. (Note it comes from the dual ofStartWith
onIObservable<T>
where we can start an event sequence with one or more initial values provided from an array.) It could be done quite easily today usingnew[] { ... }.Concat(xs)
but may be deemed a natural extension toPrepend
.Scan (aggregate yielding intermediate results)
Totally analogous signatures to
Aggregate
but yields every intermediate computed result. As usual, it comes from the duality with Rx where we deal with streams of events (that may never terminate). This said, it has value on a lazy enumerable sequence, e.g. when processing large logs and providing all intermediate aggregation values as the analysis is going on.Aggregate
is pretty muchScan
followed byLast
, only optimized.There are a bunch more that are likely a bit more esoteric and of lesser value, but nonetheless worth having a look at. One family of them deals with sharing side-effects of enumeration in a less aggressive way than the traditional
ToArray
toToList
approach; see things likeShare
,Memoize
, andPublish
.It's been a while since I've worked on / looked at this code, so some design decisions may have eroded from my memory, but I'll do my best recollecting these if questions come up.
The text was updated successfully, but these errors were encountered: