开发者

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;
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜