-
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
Add parameterless .ToDictionary() and .ToLookup() overloads to System.Linq.Enumerable #45679
Comments
Tagging subscribers to this area: @eiriktsarpalis Issue DetailsBackground and Motivation.ToDictionary() and .ToLookup are around for a long time and still very useful, sometimes it would be nicer if they could just be called without any parameters, if the usage implies what kind of dictionary/lookup is meant. See also #24900, which proposes a subset of this suggestion (the KeyValuePair part) // instead of writing
valueTupleEnumerable.ToDictionary(x=>x.key, x=>x.value)
// write
valueTupleEnumerable.ToDictionary(); Proposed APIAdd additional extension methods to System.Linq.Enumerable namespace System.Linq
{
public static partial class Enumerable
{
+ public static ILookup<TKey, TValue> ToLookup<TKey, TValue>(this IEnumerable<(TKey, TValue)> enumerable)
+ => enumerable.ToLookup(x => x.Item1, x => x.Item2);
+
+ public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<(TKey, TValue)> enumerable) where TKey : notnull
+ => enumerable.ToDictionary(x => x.Item1, x => x.Item2);
+
+ public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> enumerable) where TKey : notnull
+ => enumerable.ToDictionary(x => x.Key, x => x.Value);
}
} Usage Examplesrecord Person(int Id, string Name, int Age);
var persons = new List<Person> {
new(1, "Person 1", 22),
new(2, "Person 2", 22),
new(3, "Person 3", 30),
new(4, "Person 4", 40),
};
var personsAgeLookup = (
from person in persons
select (key: person.Age, value: person.Name)
).ToLookup();
var sameAgedPersonLookup = (
from person in persons
from sameAgedPerson in personsAgeLookup[person.Age]
where sameAgedPerson != person.Name
select (person, sameAgedPerson)
).ToLookup();
var dict = new Dictionary<int,Person>();
var newDict = dict.Where(i=>i.Key*10 == i.Value.Age).ToDictionary(); instead of var personsAgeLookup = (
from person in persons
select (key: person.Age, value: person.Name)
).ToLookup(x=>x.key, x=>x.value);
var sameAgedPersonDictionary = (
from person in persons
from sameAgedPerson in personsAgeLookup[person.Age]
where sameAgedPerson != person.Name
select (person, sameAgedPerson)
).ToDictionary(x=>x.person, x=>x.sameAgedPerson);
var dict = new Dictionary<int, Person>();
var newDict = new Dictionary<int,Person>(dict.Where(i => i.Key * 10 == i.Value.Age)); Alternative Designs
Risksnone?
|
Hi @andi0b and thank you for your proposal. How common is it that the source enumerable is of type |
I do this a fair amount (the use-case is normally constructing a KVP somewhere earlier in the linq query, then perhaps filtering it), but then pass the resulting Adding this would save me a few keystrokes, but there's a perfectly serviceable way of writing this today, so it's not a big deal. |
I also see |
This may be a better fit for System.Interactive. |
@eiriktsarpalis: I totally agree that this API change is more a nice to have, than a must. But it can save some typing. It can simplify many generation of a Dictionary or Lookup from LINQ queries. I know there is also a constructor Like @BhaaLseN already said, I also see @eiriktsarpalis: You're right, that my first example ( // query syntax
var personsAgeLookup = (
from person in persons
let key = GetKey(person)
where key % 2 == 0
select (key, value: person.Name)
).ToLookup(); // instead of .ToLookup(x=>x.key, x=>x.person)
// or method syntax
var personsAgeLookup2 = persons.Select(person=>(key: GetKey(person), person))
.Where(x=>x.key % 2 == 0)
.ToLookup(); // instead of .ToLookup(x=>x.key, x=>x.person) |
@scalablecory: I see no reason why this feature should go into System.Interactive. If it is accepted it should be available for LINQ everywhere. |
Adding new methods to LINQ comes at a cost: shared framework size. We generally don't do it unless we are able to gather substantial evidence that it provides real value to a big chunk of our users. The nice thing about LINQ is that it is extensible: just write an extension method of your own and you should be set. Even better, author a LINQ extensions nuget package that other users can enjoy. From a .NET team perspective we fully encourage community members building successful NuGet packages for the ecosystem. |
@eiriktsarpalis: totally understandable if this is declined because it will just bloat the framework unnecessarily. I just always get annoyed by this particular missing functionality. And I try not to use non-standard Linq methods/extensions, because code is less readable then. The reader may not know the particular library I used and has to look it up. |
Thank you for understanding. I'm going to close this issue but as always feel free to reopen if you feel there is more to be added to this conversation. |
Background and Motivation
.ToDictionary() and .ToLookup are around for a long time and still very useful, sometimes it would be nicer if they could just be called without any parameters, if the usage implies what kind of dictionary/lookup is meant.
See also #24900, which proposes a subset of this suggestion (the KeyValuePair part)
Proposed API
Add additional extension methods to System.Linq.Enumerable
Usage Examples
instead of
Alternative Designs
Tuple<T1,T2>
?AsDictionary
andAsLookup
?Risks
none?
The text was updated successfully, but these errors were encountered: