C# 删除foreach-c代码优化

C# 删除foreach-c代码优化,c#,foreach,ilist,optimization,C#,Foreach,Ilist,Optimization,如何优化此代码 ParentDoglist,ChildDoglistis-Ilist。列表框-列表框 foreach (Dog ParentDog in ParentDoglist) { foreach (Dog ChildDog in ChildDoglist) { if(ParentDog.StatusID==ChildDog.StatusID) dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key));

如何优化此代码

ParentDoglist,ChildDoglistis-Ilist。列表框-列表框

foreach (Dog ParentDog in ParentDoglist)
{
 foreach (Dog ChildDog in ChildDoglist)
 {
  if(ParentDog.StatusID==ChildDog.StatusID)
  dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key));
 }
}
编辑: ParentDogTypeList、DogTypeList被重命名为ParentDoglist、ChildDoglist,两者互不相关

if(ParentDog.Key==ChildDog.Key)
改为

if(ParentDog.StatusID==ChildDog.StatusID)
完整故事:

我需要填充一个下拉列表,它将返回父子关系。有一些狗可能没有孩子,这将被称为叶狗。我还需要显示这类狗的数量

DD看起来像

Parent1
  Child11 (10)
  Child12 (12)
Parent2
  Child21 (23)
  Child22 (20)
Leaf1 (20)
Leaf2 (34)
因此,ParentDoglist将带来所有子元素和叶元素以及计数,而ChildDogList将具有父元素和叶ID,因此我将能够将相应的子元素填充到它们的父元素,并直接绑定叶

父、子和叶狗将在一个表中维护,并通过statusid和count在另一个表中进行区分

没有父项将有任何计数,只有子项和叶将有计数

表架构:

您可以对ParentDoglist和ChildDoglist进行排序,并在^2上执行线性查找算法(不包括该算法)

但是您可以在OParentDoglist.Size+ChildDoglist.Size*log2ParentDoglist.Size+ChildDoglist.Size中对容器进行排序

如果只运行一次代码,那么您的算法是最优的。 但是,如果您要搜索多次,最佳解决方案是对容器进行排序,并在线性时间内进行比较,但是如果您的容器可以更改,则搜索函数已更改,并且您使用多次解决方案,则必须使用容器来承载此元素,因为在容器更改后使用普通列表,您无法在Ologn时间内返回到排序状态


这就是使用LinQ的方法,您最大的问题可能是dogListBox.Items.Add。一次添加一个项目相当昂贵。它的效率更高

要使内循环小得多,可以为内循环中的键创建查找

List<ListItem> listItems = new List<ListItem>();
ILookup<string, Dog> childDogsPerKey = ChildDoglist.ToLookup(dog => dog.Key);
foreach (Dog ParentDog in ParentDoglist)
{
    foreach (Dog ChildDog in childDogsPerKey[ParentDog.Key])
    {
        listItems.Add(new ListItem(ParentDog.Name, ParentDog.Key));
    }
}
dogListBox.Items.AddRange(listItems.ToArray());

此代码假定多个子狗可以具有相同的密钥。如果每个密钥只能有一个子狗,您可以改用它,因为它来自数据库,数据库往返可能是性能杀手。此外,ParentDog.Key==ChildDog.Key的比较也可以在SQL中完成,因此您不会将所有数据拉到应用程序中只是为了丢弃它

重新设计此选项,以便在一个查询中执行单个选择以获取所有数据

Albin提到了AddRange,但您甚至可以更进一步,虚拟化网格,这样当用户查看网格的那部分时,它只会向用户显示行

编辑

要生成列表,您似乎需要从数据库返回如下内容:

Parent1, null, null Parent1, Child1, 110 Parent1, Child12, 12 Parent2, null, null Parent2, Child21, 23 Parent2, Child22 ,20 Leaf1, null, 20 Leaf2, null, 34
这看起来需要某种左连接和计数,并加入一个潜在的联合。

速度慢的不是foreach,而是添加和呈现新项目

添加beginupdate/endupdate:

dogListBox.BeginUpdate();
foreach (Dog ParentDog in ParentDoglist) 
{ 
 foreach (Dog ChildDog in ChildDoglist) 
 { 
  if(ParentDog.Key==ChildDog.Key) 
  dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key)); 
 } 
} 
dogListBox.EndUpdate();

我仍然认为最优雅和优化的方法是使用Linq

box.Items.AddRange(
   ParentDoglist.Where(p=>ChildDoglist.Any(c=>c.StatusID== p.StatusID))
    .Select(r=>new ListItem(r.StatusID, r.Name)).ToArray());
就这些,只有一行。 如果您更喜欢联接,可以使用该查询来实现

box.Items.AddRange(
   ParentDoglist.Join(ChildDoglist, p => p.StatusID, c => c.StatusID, (p,c)=>p)
    .Select(r=>new ListItem(r.StatusID, r.Name)).ToArray());

可以用简单的Linq表达式替换嵌套的foreach循环。要使其工作,您需要使用System.Linq

foreach (Dog ParentDog in 
            (from dog in ParentDogList
             from ChildDog in dog.StatusId
             where dog.StatusId == ChildDog.StatusId)
             select dog) )
{
    dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key));
}

DogTypeList是所有狗类型的列表,ParentDogTypeList是狗类型的子集吗?这些列表来自数据库吗?@Sam Saffron是的,这两个列表都来自DB。@Preet Sangha我有三个以上相同类型的内部foreach,所以我想减少foreach@Sri,那么您是否可以编辑问题并在此处包含表的db模式。直接查询很可能是最快的,它不是仍然有隐式嵌套循环吗?它仍然在^2;-仅在ChildDoglist容器中使用lazy foreach,没有任何优化。同意AddRange可能会有很大帮助。编辑我的问题以准确解释完整的问题,但如何在没有任何循环的情况下填充列表框?@Sri,一个查询和一个循环,如果没有表模式和您正在使用的SQL flavor,我就无能为力了假设SQL Server更新为模式我使用MysqlI使用了两个查询,其中一个查询将获取leaf和child的计数。另一个用于获取类别,这将有助于找到哪个孩子属于哪个家长!
foreach (Dog ParentDog in 
            (from dog in ParentDogList
             from ChildDog in dog.StatusId
             where dog.StatusId == ChildDog.StatusId)
             select dog) )
{
    dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key));
}