How to chunk dictionary by Linq in C#?
I have a dictionary, which i need to chunk to list of 9 diction开发者_如何转开发ary item in a group and other 9 items in to next group and so on...,
Tried this code,
public static List<List<DictionaryEntry>> ChunkDict(Dictionary<string,string> theList, int chunkSize)
{
List<List<DictionaryEntry>> result = theList.Select((x, i) =>
new { data = x, indexgroup = i / chunkSize })
.GroupBy(x => x.indexgroup, x => x.data)
.Select(g => new List<DictionaryEntry>(g)).ToList();
return result;
}
But it is not compiling, got error: Error 398 The best overloaded method match for 'System.Collections.Generic.List.List(System.Collections.Generic.IEnumerable)' has some invalid arguments
How do i do this?
I wrote this a while back to do exactly that:
public static class EnumerableExtensions
{
public static IEnumerable<IEnumerable<TElement>> Partition<TElement>(this IEnumerable<TElement> @this, int partitionSize)
{
if (@this == null) throw new ArgumentNullException("this");
return new PartitionedEnumerable<TElement>(@this, partitionSize);
}
private sealed class PartitionedEnumerable<TElement> : IEnumerable<IEnumerable<TElement>>
{
#region Public
public PartitionedEnumerable(IEnumerable<TElement> elements, int partitionSize)
{
this.elements = elements;
this.partitionSize = partitionSize;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<IEnumerable<TElement>> GetEnumerator()
{
IEnumerator<TElement> elementEnumerator = this.elements.GetEnumerator();
var partition = new List<TElement>();
while (elementEnumerator.MoveNext())
{
partition.Add(elementEnumerator.Current);
if (partition.Count == partitionSize)
{
yield return partition;
partition = new List<TElement>();
}
}
if (partition.Count > 0) yield return partition;
}
#endregion
#region Private
private readonly IEnumerable<TElement> elements;
private readonly int partitionSize;
#endregion
}
}
Example:
IDictionary<string, string> dictionary = ...;
foreach (IEnumerable<KeyValuePair<string, string>> triplet in dictionary.Partition(3))
{
... // use the triplet
}
If you want them back as dictionaries:
IEnumerable<Dictionary<string, string>> partitioned = dictionary.Partition(3)
.Select(_ => _.ToDictionary());
Using the example code from this answer:
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
{
int i = 0;
var splits = from name in list
group name by i++ % parts into part
select part.AsEnumerable();
return splits;
}
Perhaps you can modify it to work for your Dictionary list.
Have you tried this?
public static Dictionary<int,List<Dictionary<string,string>> ChunkDict(Dictionary<string,string> theList, int chunkSize)
{
var result = theList.Select((x, i) =>
new { data = x, indexgroup = i / chunkSize })
.GroupBy(x => x.indexgroup)
.Select(new KeyValuePair<int, List<Dictionary<string,string>>>(x.Key, x.ToList())).ToDictionary();
return result;
}
EDIT:
Probally a little modification needed, I haven't even compiled this code.
here is a chunking algorithm I wrote that may help you
public static IEnumerable<IEnumerable<TResult>> SelectChunk<TSource, TResult>(
this IEnumerable<TSource> source, Func<TSource, TResult> selector, int chunkSize)
{
IEnumerator<TSource> enumerator = source.GetEnumerator();
while(true)
{
if (!enumerator.MoveNext())
break;
var resultArray = new TResult[chunkSize];
for (int i = 0; i < chunkSize; i++)
{
resultArray[i] = selector(enumerator.Current);
if (i == chunkSize-1 || !enumerator.MoveNext())
break;
}
yield return resultArray;
}
}
EDIT
And heres how you use it:
dictionary.SelectChunk(s => s, 9).Select(s => s.ToList).ToList()
You are not accessing the data from the group item, try this:
public static void Main(string[] args)
{
var dict = new Dictionary<string, string> { { "1", "one" }, { "2", "two" }, { "3", "three" }, { "4", "four" }, { "5", "five" }, { "6", "six" } };
var lists = ChunkDict(dict, 2);
var i = 0;
foreach (var list in lists)
{
Console.WriteLine("List with index {0} has count {1}", i, list.Count);
foreach (var dictionaryEntry in list)
{
Console.WriteLine(dictionaryEntry.Key + ": " + dictionaryEntry.Value);
}
i++;
}
Console.ReadLine();
}
public static List<List<KeyValuePair<string, string>>> ChunkDict(Dictionary<string, string> theList, int chunkSize)
{
var result = theList.Select((x, i) =>
new { data = x, indexgroup = i / chunkSize })
.GroupBy(x => x.indexgroup, x => x.data)
.Select(y => y.Select(x => x).ToList()).ToList();
return result;
}
精彩评论