-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[API Proposal]: Add overload of ToDictionary that turns an IEnumerable of KeyValuePair or ValueTuple #65925
Comments
Tagging subscribers to this area: @dotnet/area-system-collections Issue DetailsBackground and motivationSometimes in parsing it's common transform key value pairs expressed as text into a dictionary pretty concise LINQ statement: Consider a query string parser (a=b&c=d&e=f). Dictionary<string, string> Parse(string query) =>
query.Split('&')
.Select<string, (string? k, string? v)?>(s => s.Split('=') switch // This part is gross 😢
{
[var k, var v] => (k, v),
_ => null,
})
.Where(p => p is not null)
.Select(p => p!.Value)
.ToDictionary(p => p.k!, p => p.v!); The last ToDictionary call wouldn't require explicitly mapping the key and value for this common case. API Proposalnamespace System.Collections.Generic;
public static partial class Enumerable
{
public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(this IEnumerable<KeyValuePair<TSource, TKey>> source) where TKey : notnull;
public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(this IEnumerable<ValueTuple<TSource, TKey>> source) where TKey : notnull;
} API Usage// Fancy the value
var c = new List<(string, int)>();
c.Add(("one", 1));
c.Add(("two", 2));
c.Add(("three", 3));
var map = c.ToDictionary();
// Getting the values out
foreach (var (key, value) in map)
Console.WriteLine($"{key} = {value}"); Alternative DesignsNo response RisksNo response
|
I think TKey is misplaced and TSource is misleading. What should last code print in your opinion? "one = 1"? or "1 = one"? In linq naming conventions, TSource would be KVP<K, V> or VT<V1, V2>, not K or V1. |
The most intuitive thing would be one = 1 😄. At least that was the intent.
|
Do you envision other benefits from this besides the fewer key strokes? Should there also be overloads taking an |
Sounds reasonable, proposal should probably also include equivalent IQueryable overloads cc @krwq |
Haven't thought about the other potential savings.
Possibly yes.
Do we also have ToDictionary on IQueryable? Seems strange no? |
I'm asking since I recall(?) the bar of adding generic overloads to |
Ah yes you're right, not applicable to |
The proposal seems complete and I'm not strongly opinionated on this so I'll let API reviewers decide if we want this or not. I've personally wrote similar code in the past as mentioned so I guess it is occasionally very useful. |
To make sure I understand the proposal, this would simply be to enable you to write: .ToDictionary() instead of .ToDictionary(p => p.Key, p => p.Value) ? Is this scenario really common enough to warrant that? If you're parsing and you care about perf, you shouldn't be using LINQ for that in the first place, so presumably perf isn't really the argument here, and it's just the usability / discoverability? Personally I'd want to see compelling evidence that this is a common use case. (I see some examples in source.dot.net, but a bunch of the uses of that overload actually transform the key or value, while others shouldn't be using ToDictionary at all and should instead just use Dictionary's copy ctor.) |
Yes I have no idea how common it is in the wild, I've been using this pattern more recently with tuples and LINQ so I figured I'd file an issue. |
The proposal should probably include overloads that accept an |
Updated |
IMO we should use named tuples wherever possible, so this would be |
It might be worth mentioning that there is already an extension method There's another issue that suggests adding overloads that take |
@davidfowl |
I could definitely use this as I've already written the code to do these things. It makes initializing a dictionary so much more convenient. |
namespace System.Collections.Generic;
public static partial class Enumerable
{
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> source) where TKey : notnull;
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> source, IEqualityComparer<TKey> comparer) where TKey : notnull;
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<(TKey Key, TValue Value)> source) where TKey : notnull;
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<(TKey Key, TValue Value)> source, IEqualityComparer<TKey> comparer) where TKey : notnull;
} |
Hi, PR is marked as ready for review now, thanks. |
Background and motivation
Sometimes in parsing it's common transform key value pairs expressed as text into a dictionary pretty concise LINQ statement: Consider a query string parser (a=b&c=d&e=f).
The last ToDictionary call wouldn't require explicitly mapping the key and value for this common case.
API Proposal
API Usage
Alternative Designs
No response
Risks
No response
The text was updated successfully, but these errors were encountered: