【问题标题】:Convert Dictionary<string,List<foo>> to List<foo> in C# 2.0在 C# 2.0 中将 Dictionary<string,List<foo>> 转换为 List<foo>
【发布时间】:2010-10-27 21:34:09
【问题描述】:

有没有其他方法可以直接从 ValueCollection 获取List&lt;foo&gt;。

当前我正在使用以下代码

 Dictionary<string,List<foo>> dic;

 List<foo> list= new List<foo>();

 foreach (List<foo> var in dic.Values)
 {               
      list.AddRange(var);
 }  

或

List<List<foo>> list= new List<List<foo>>(dic.Values);

上面的转换给了我List&lt;List&lt;foo&gt;,但我希望 dic.values 中的List&lt;foo&gt; 不使用 for 每个循环,如果可能的话,使用 .NET 2.0。

【问题讨论】:

  • 为什么不想使用 foreach 循环?
  • 如果没有 Linq (.NET 3.5),您将需要一个 for 或 foreach 循环。
  • 根据您的要求,您可以链接到 .NET 3.0/3.5,但仍可在旧版本的 Visual Studio 上进行编译。该语法看起来不那么性感,因为您必须通过静态语法访问扩展方法,但它至少是一种替代方法。
  • @Greg,通过为它实现自己的类,可以不用 for 或 foreach 循环。
  • @tster - 然后循环在自定义类或自定义方法中。正如我所说,您仍然需要在 somewhere 编写一个循环 - 除非您使用递归或其他一些杂技来避免它。只需在原地或在实用程序/扩展方法中使用foreach 循环即可完成。

标签: c# list dictionary


【解决方案1】:

不使用 LINQ 或 .NET 3.5,如果没有某种 for 循环,我不知道有什么方法可以做到这一点。即使使用 LINQ,在框架中的某处 foreach 也会做同样的事情。

如果您链接到 .NET 2.0 但可以访问更高的 C# 编译器版本,则可以使用 LinqBridge.dll 来实现相同的效果 - 请阅读 here。请注意,这至少需要 VS 2008(针对 2.0 框架)。如果你可以使用它,那么你所要做的就是

using System.Linq;

...

dic.Values.SelectMany(v => v).ToList();

【讨论】:

  • LINQ 至少会将 foreach 推到迭代时间而不是创建时间。
  • 是的 - 我怀疑真正的胜利是 OP 不必自己编写!使用 LinqBridge,也可以使用 2.0 框架。
【解决方案2】:

编辑:简单的 LINQ 解决方案(在 .NET 2.0 中不可用)

dic.Values.SelectMany(list => list).ToList()

如果您不需要 List 并且可以使用 IEnumerable,则不要使用 ToList()

更难的解决方案:

  1. 定义一个实现 IList 的类,该类具有一个构造函数,该构造函数采用 ValueCollection 或 ICollection
  2. 在其上实现所有方法。您可以跟踪所有 T 列表以及您正在处理的当前列表的索引。

使用

return new MyListCombiner<foo>(dict.Values);

【讨论】:

  • OP 特别提到了.NET 2.0。
  • @Don Kirby:标题说 C# 2.0。没关系,我不是要吹毛求疵。
  • @Don Kirkby,我读到“如果可能”是指使用 foreach 循环,但并不完全清楚。
  • 我认为你是对的,@adrift,我可能误解了这一点。
【解决方案3】:

你的 foreach 循环应该是

Dictionary<string,List<foo>> dic;

 List<foo> list= new List<foo>();

 foreach (List<foo> var in dic.Values)
 {    
      foreach(foo bar in var){           
          list.AddRange(bar);
      }
 }  

当您想将每个列表的每个项目添加到列表时,您正在将每个列表添加到列表中。

并且完全错过了您问题中的 for each 循环部分。

我认为这在 C# 2.0 中是不可能的。 LINQ 的核心只是在 IEnumerable 上进行迭代,而这正是 foreach 正在做的事情

【讨论】:

  • 根据此引用msdn.microsoft.com/en-us/library/z883w3dc.aspxAddRange 将作为IEnumerable&lt;T&gt; 传递给它的集合的元素添加到列表中,因此OP 的代码是正确的
  • @Maciej Hehl 这是真的,现在我想试试这个,看看为什么它没有达到应有的效果。
【解决方案4】:

最终,您选择的任何方法都将涉及某种抽象级别的 for 循环。如果您停留在纯 .NET 2.0 中,则必须在代码中的某处编写该 for 循环。这种数据聚合是 LINQ 的主要目的之一。见SelectMany方法:

http://msdn.microsoft.com/en-us/library/system.linq.enumerable.selectmany.aspx

根据您的要求,您可以链接到 .NET 3.0/3.5,但仍可在旧版本的工具集上进行编译。您仍然必须在运行应用程序的机器上安装 3.0/3.5,但不必升级您的工具。该语法也不会看起来那么性感,因为您必须通过静态方法语法访问扩展方法。

【讨论】:

    【解决方案5】:

    在 C# 2.0 中,您必须使用循环或 Poor Man's LINQ,代码如下所示:

    Linq(dic.Values).SelectMany(delegate(List<foo> list) { return list; }).ToList()
    

    你定义 Linq() 的地方

    static PoorMansLinq<T> Linq<T>(IEnumerable<T> source)
    {
        return new PoorMansLinq<T>(source);
    }
    

    我注意到第一行当前不起作用,我提交了更新以修复它。同时,您可以使用以下解决方法:

    Linq(Linq(dic.Values).SelectMany(delegate(List<foo> list) { return list; })).ToList()
    

    你也可以使用LinqBridge,直接调用Enumerable,但是如果没有C# 3.0,这很麻烦。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-19
      • 2018-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-28
      相关资源
      最近更新 更多