Reputation: 1419
I have a List
List<string> sList = new List<string>() { "a","b","c"};
And currently I am selecting this into a dictionary the following structure:
//(1,a)(2,b)(3,c)
Dictionary<int, string> dResult = new Dictionary<int, string>();
for(int i=0;i< sList.Count;i++)
{
dResult.Add(i, sList[i]);
}
but with Linq I've seen some slimmer way like ToDictionary((x,index) =>
How is the correct syntax or how can this be solved within one line?
Upvotes: 15
Views: 7949
Reputation: 1500675
There's no ToDictionary
method that gives this in a single call, as there are no overloads that provide the index, but you can use the Select
overload which accepts a Func<T, int, TResult>
:
var dictionary = list.Select((value, index) => new { value, index })
.ToDictionary(pair => pair.index, pair => pair.value);
Or in C# 7, avoiding creating a bunch of heap-allocated objects using ValueTuple
:
var dictionary = list.Select((v, i) => (value: v, index: i))
.ToDictionary(pair => pair.index, pair => pair.value);
As of C# 7.1 point release, you can use the inferred ValueTuple
literal expression:
var dictionary = list.Select((value, index) => (value, index))
.ToDictionary(pair => pair.index, pair => pair.value);
(As noted by Tim, you'll need to adjust the index by 1 to get the original requested output.)
Upvotes: 12
Reputation: 460138
You can use the overload of Select
that projects the index to fill an anonymous type:
Dictionary<int, string> dResult = sList
.Select((s, index) => new { s, index })
.ToDictionary(x => x.index, x => x.s);
That is the same as what your code does. If you instead want the result you've commented: (1,a)(2,b)(3,c)
) you have to add +1 so ToDictionary(x => x.index+1, x => x.s)
.
Upvotes: 27
Reputation: 37000
First you have to get the key and value using the select-overload that also provices the index of the currently used element:
var tmp = sList.Select((x, i) => new { Key = i, Value = x });
Now create the dictionary:
var result = tmp.ToDictionary(x => x.Key, x => x.Value);
Or as a one-liner:
var result = sList.Select((x, i) => new { Key = i, Value = x }).ToDictionary(x => x.Key, x => x.Value);
EDIT: You can also create your own extension-method to also use the syntax you provided:
public static Dictionary<TResultKey, TResultValue> ToDictionary<TSource, TResultKey, TResultValue>(this IEnumerable<TSource> src, Func<TSource, int, TResultKey> KeySelector, Func<TSource, int, TResultValue> ValueSelector)
{
var result = new Dictionary<TResultKey, TResultValue>();
int i = 0;
foreach (var element in src)
{
result[KeySelector(element, i)] = ValueSelector(element, i);
i++;
}
return result;
}
Now you can call it like this:
List<string> sList = new List<string>() { "a","b","c"};
var result = sList.ToDictionary((x, i) => i + 1, (x, i) => x);
Upvotes: 3
Reputation: 121
You can also use this approach without an anonymous type:
Dictionary<int, string> dResult = Enumerable
.Range(0, sList.Count())
.ToDictionary(i => i + 1, i => sList[i]);
Upvotes: 4