在C# 2.0中将Dictionary<string,List<foo>>转换成List<foo>

4

有没有其他直接从 ValueCollection 获取 List<foo> 的方法。

目前我正在使用以下代码:

 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<List<foo>>,但是我想从dic.values中得到List<foo>,如果可能的话,不使用for each循环,使用.NET 2.0。

1
为什么你不想使用 foreach 循环? - kevingessner
1
如果没有Linq(.NET 3.5),你需要在某个地方使用forforeach循环。 - Greg
根据您的需求,您可以链接到.NET 3.0/3.5,但仍然可以在旧版本的Visual Studio上编译。语法看起来可能不太好看,因为您必须通过静态语法访问扩展方法,但这至少是一种选择。 - Merlyn Morgan-Graham
@Greg,可以通过实现自己的类来避免使用for或foreach循环。 - tster
@tster - 然后循环在自定义类或自定义方法中。正如我所说,您仍然必须在某个地方编写循环——除非您使用递归或其他巧妙的技巧来避免它。只需在原地或实用程序/扩展方法中使用foreach循环即可完成。 - Greg
5个回答

2

如果不使用LINQ或.NET 3.5,我不知道有什么方法可以在没有任何类型的for循环的情况下完成此操作。即使使用LINQ,在框架中也会有一个foreach执行相同的操作。

如果你被限制在.NET 2.0上,但可以访问更高版本的C#编译器,则可以使用LinqBridge.dll来实现相同的效果-在这里了解更多信息。请注意,这将需要至少VS 2008(针对2.0框架)。如果您可以使用它,那么您只需要执行以下操作:

using System.Linq;

...

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

LINQ 至少会将 foreach 推迟到迭代时间而不是创建时间。 - tster
真的 - 我认为真正的胜利在于OP不必自己编写它!有了LinqBridge,即使使用2.0框架也是可能的。 - Ben

1

编辑:简单的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版本。 - Ani
1
@Don Kirby:标题说的是C# 2.0。没关系,我不是要挑剔。 - Ani
@Don Kirkby,我认为“如果可能”的意思是使用foreach循环,但并不完全清楚。 - Jeff Ogata
我认为你是对的,@adrift,我可能误解了那个。 - Don Kirkby

1
您的 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 所做的所有事情。


根据此参考文献http://msdn.microsoft.com/en-us/library/z883w3dc.aspx,`AddRange`将传递给它作为`IEnumerable<T>`的集合的元素添加到列表中,因此OP的代码是正确的。 - Maciej Hehl
@Maciej Hehl 这是真的,现在我想试着玩一下,看看为什么它没有做它应该做的事情。 - msarchet

0
在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 的情况下会很繁琐。


0

最终,任何你选择的方法都将涉及到某个抽象层次上的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,但不必升级您的工具。语法也不会看起来那么好看,因为您必须通过静态方法语法访问扩展方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接