【问题标题】:How to chunk dictionary by Linq in C#?如何在 C# 中通过 Linq 对字典进行分块?
【发布时间】:2011-08-23 13:27:40
【问题描述】:

我有一本字典,我需要将其分块以列出一组中的 9 个字典项和下一组中的其他 9 个项,依此类推...,

试过这段代码,

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

但它没有编译,出现错误:错误 398 'System.Collections.Generic.List.List(System.Collections.Generic.IEnumerable)' 的最佳重载方法匹配有一些无效参数

我该怎么做?

【问题讨论】:

  • “它没有按预期工作”是什么意思?
  • 你最终得到一个字典条目列表,而不是字典列表(也许这就是你想要的)?
  • 编译错误,错误 398 最佳重载方法匹配 'System.Collections.Generic.List.List(System.Collections.Generic.IEnumerable)' 有一些无效的参数

标签: c# linq


【解决方案1】:

我写这篇文章是为了做到这一点:

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

例子:

IDictionary<string, string> dictionary = ...;
foreach (IEnumerable<KeyValuePair<string, string>> triplet in dictionary.Partition(3))
{
    ... // use the triplet
}

如果您希望它们作为字典返回:

IEnumerable<Dictionary<string, string>> partitioned = dictionary.Partition(3)
                                                                .Select(_ => _.ToDictionary());

【讨论】:

  • 'this' 关键字前面的 @ 符号的用途是什么。不批评,我真的不知道这是为了什么。谢谢。
  • 这是一个保留关键字。如果你想像保留关键字一样命名你的变量,你需要在变量名前加上@符号。
  • @Darren Young:@ 允许将 C# 关键字用作符号名称。我在扩展方法中使用@this 作为约定,因为扩展方法就像目标类型上的合成实例方法,例如上例中的IEnumerable
  • @Dhana:为了清晰起见,我添加了一个静态类包装器。您需要将静态类放在您选择的命名空间中。扩展方法将作为任何 IEnumerable 上的方法可用,该方法使用静态类所在的命名空间。
  • 谢谢两位。我现在比昨天更好了 :)
【解决方案2】:

使用来自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;
}

也许您可以修改它以适用于您的字典列表。

【讨论】:

    【解决方案3】:

    你试过了吗?

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

    编辑:

    可能需要一点修改,我什至没有编译这段代码。

    【讨论】:

      【解决方案4】:

      这是我写的一个分块算法,可以帮助你

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

      编辑

      下面是你如何使用它:

      dictionary.SelectChunk(s => s, 9).Select(s => s.ToList).ToList()
      

      【讨论】:

        【解决方案5】:

        您没有访问组项目中的数据,试试这个:

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

        【讨论】:

        • 错误:错误 398 'System.Collections.Generic.List.List(System.Collections.Generic.IEnumerable 的最佳重载方法匹配)' 有一些无效的参数
        • 查看更新的代码,而不是使用DictionaryEntry,您可以使用KeyVauePair&lt;string,string&gt;。但我仍然想知道你为什么要这样做。
        猜你喜欢
        • 2018-08-14
        • 2016-05-30
        • 1970-01-01
        • 2016-01-16
        • 2017-05-13
        • 2015-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多