C# 删除foreach-c代码优化
如何优化此代码 ParentDoglist,ChildDoglistis-Ilist。列表框-列表框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));
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));
}