如何优化此代码?
ParentDoglist,ChildDoglistis - Ilist。 dogListBox - 列表框
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将带来所有Child和leaf元素以及count和ChildDogList将具有Parent和leaf ID,因此我可以将相应的Child填充到其Parent并直接绑定叶子。
父母,儿童和叶子狗将保留在一个表格中,并通过statusid进行区分,计数将在另一个表格中。
没有父母会有任何计数,只有孩子和叶子会有计数
表架构:
答案 0 :(得分:8)
您可以对ParentDoglist
和ChildDoglist
进行排序,并对此O(n)
执行线性O(n^2)
查找算法。
但您可以在O((ParentDoglist.Size() + ChildDoglist.Size()) * log2(ParentDoglist.Size() + ChildDoglist.Size()))
中对容器进行排序。
然后,如果您运行此代码 ONCE ONLY ,您的算法最佳。
但是,如果您正在搜索超过一次,最佳解决方案是对容器进行排序并在线性时间内进行比较,但是如果您的容器可以更改,那么搜索功能就会被改变并且您使用“不止一次”时间解决方案“您必须使用 RB-Tree 容器来携带此元素,因为在容器更改后的正常列表中,您无法在O(log(n))
时间内返回到已排序状态。
答案 1 :(得分:2)
你最大的问题可能是dogListBox.Items.Add
。一次添加一个项目非常昂贵。 ListBox.Items.AddRange
效率更高。
要使内循环更小,可以在内循环中为键创建查找。
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());
此代码假设有几只幼犬可以拥有相同的密钥。如果每个键只能有一只幼犬,则可以使用.ToDictionary()
代替
答案 2 :(得分:2)
我仍然认为最优雅和最优化的方法是使用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());
答案 3 :(得分:1)
由于这是来自数据库,数据库往返可能是性能杀手。此外,比较ParentDog.Key==ChildDog.Key
可以在SQL中完成,因此您不会将所有数据提取到您的应用只是为了丢弃它。
重新设计,以便您进行一次选择以获取一个查询中的所有数据。
Albin提到了AddRange,但你甚至可以更进一步,虚拟化你的网格,这样它只会在看到网格的那一部分时拉出显示给用户的行。
修改强>
要生成列表,您似乎需要从DB中返回类似的内容:
Parent1, null, null Parent1, Child1, 110 Parent1, Child12, 12 Parent2, null, null Parent2, Child21, 23 Parent2, Child22 ,20 Leaf1, null, 20 Leaf2, null, 34
看起来您需要某种left join
和count
,并且可能会引入union all
。
答案 4 :(得分:1)
这不是一个缓慢的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();
答案 5 :(得分:0)
您可以使用简单的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));
}
答案 6 :(得分:-1)
foreach (var ParentDog in ParentDoglist.Where(p=>ChildDoglist.Any(c=>c.Key== p.Key)).ToList())
dogListBox.Items.Add(new ListItem(ParentDog.Name, ParentDog.Key));
这就是你用LinQ做的方法