C#嵌套foreach循环优化

4

我有一个嵌套的foreach循环,需要缩短计算时间。每个集合大约有50个成员,所以外推很大。我看了很多关于SelectMany的信息,但我仍然不确定如何使用它,或者它是否是正确的解决方案。

List<string> StringList; //Populated in previous code
Type[] assemblyTypes = RandomAssembly.GetTypes();

foreach (String name in StringList)
{                               
  foreach (Type at in assemblyTypes)
  {                             
    if (name == at.Name)
    {                                       
      //Do stuff.
    }
  }
}

谢谢您的提前帮助!

5个回答

4
使用查找表(例如字典)可以增加检查类型名称的速度:
List<string> StringList; //Populated in previous code
Dictionary<string,Type> assemblyTypes = RandomAssembly.GetTypes()
    .ToDictionary(t => t.Name, t => t);

foreach (String name in StringList)
{                               
    if (assemblyTypes.ContainsKey(name))
    {                                       
      //Do stuff.
    }
  }
}

您还应该检查哪个集合中的2个 (StringListassemblyTypes) 更有可能变得更大。通常希望将较大的集合转换为查找以减少迭代次数。


1
顺便提一下,您可能需要将其调整为使用t.FullName,因为具有不同命名空间中的常见控件的库可能会导致字典键冲突。 我的假设是OP需要在StringList变量中考虑这一点。 - Joel Etherton
@JoelEtherton 说得好,但他指出字符串列表来自其他地方(并在示例中使用了.Name),所以我现在将保留帖子。 - Steve Greatrex
@SteveGreatrex 这个方法看起来是正确的,但还是有点费力。StringList最多有40个成员,并且它需要成为父循环,因为“做事情”部分需要按顺序进行。减少StringList的大小可以大大减少计算时间,但这不是真实世界的情况。有什么想法吗? - sburke1988
如果我们只谈论StringList中的40个成员,那么我会感到惊讶,如果是对该列表进行迭代导致问题。两个问题:StringList中有多少项在assemblyTypes集合中;以及“做一些事情”是什么意思?考虑到它稍微改变了问题,将该信息放在另一个问题中并在此处发布链接可能是一个好主意。 - Steve Greatrex
@SteveGreatrex http://stackoverflow.com/questions/7732948/high-computation-time 所有在StringList中的项目都在assemblyTypes中,并且assemblyTypes中只有更多的类定义。 - sburke1988

2
将Type[]加载到字典或哈希集合中(取决于您的.NET版本),然后内部循环就消失了。
List<string> StringList; //Populated in previous code
Type[] assemblyTypes = RandomAssembly.GetTypes();
Dictionary<String,Type> typesHash = new Dictionary<String,Type>();
foreach ( Type type in assemblyTypes ) {
  typesHash.Add( type.Name, type );
}

foreach (String name in StringList) {                               
  Type type = null;
  if ( typesHash.TryGetValue( name, out type ) ) {
    // do something with type
  }
}

内部循环并没有消失,它只是嵌入在哈希的TryGetValue方法中。但是,在循环的那一部分中使用哈希进行了减少搜索。 - Joel Etherton

0
你可以尝试类似这样的代码:
assemblyTypes.Where(x => StringList.Contains(x.Name));

请记住,这是区分大小写的并忽略空格,因此如果有问题,您需要添加大小写考虑或修剪。

编辑:(循环使用示例)

foreach (Type item in assemblyTypes.Where(x => StringList.Contains(x.Name)))
{
    // Do stuff
}

这仍会导致代码针对程序集中的每种类型迭代一次StringList,而字典将会更快。 - Steve Greatrex
@Steve Greatrex:我没有选择类型(OP选择了List<string>),但即使使用字典,您也必须使用x.Keys.Contains(它与我的示例执行相同的操作)或通过直接访问键值来提供更多代码给谓词。我不确定收益是否值得,但我对涉及两者的OP基准测试很感兴趣。 - Joel Etherton
如果您使用 Dictionary<string,Type>,则可以使用 ContainsKey 方法,在内部使用哈希查找键。特别是对于较大的集合,ContainsKey 的速度将比迭代 Keys 集合要快得多。 - Steve Greatrex
@Steve:当你第一次提到 List<string> 时,我认为你的意图是改变该对象而不是使用字典来控制类型。这种访问方法将在该级别上创建更快的键检查。 - Joel Etherton

0

0

最优化可能是通过查询实现的接口而不是名称来实现的。

确保您正在优化代码的正确问题/部分。


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