7

如何优化这段代码?

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 会将所有子元素和叶子元素与计数一起带来,而 ChildDogList 将具有父元素和叶子 ID,因此我将能够将相应的子元素填充到它们的父元素并直接绑定叶子。

Parent、Child 和 Leaf Dog 将保存在一个表中,并通过 statusid 进行区分,而 count 将在另一个表中。

没有父母有任何计数,只有孩子和叶子有计数

表架构:

替代文字

4

7 回答 7

8

您可以对此进行排序ParentDoglistChildDoglist执行线性O(n)查找算法O(n^2)

但是您可以将容器分类为O((ParentDoglist.Size() + ChildDoglist.Size()) * log2(ParentDoglist.Size() + ChildDoglist.Size())).

然后,如果您只运行此代码一次,您的算法就是最优的。但是,如果您搜索不止一次,最佳解决方案是对容器进行排序并在线性时间内进行比较,但是如果您的容器可以更改,则启动搜索功能并且您使用“不止一次时间解决方案”,您必须使用RB - 携带这些元素的树容器,因为容器更改后的正常列表无法及时返回排序状态O(log(n))

于 2010-08-31T11:07:34.660 回答
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()改用

于 2010-08-31T11:25:52.183 回答
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());
于 2010-08-31T12:47:11.773 回答
1

由于这来自数据库,因此数据库往返可能会成为性能杀手。此外,比较ParentDog.Key==ChildDog.Key可以在 SQL 中完成,因此您不会将所有数据拉到您的应用程序中只是为了丢弃它。

重新设计它,这样您就可以通过一次选择来获取一个查询中的所有数据。

Albin 提到了 AddRange,但您甚至可以更进一步并虚拟化您的网格,以便仅在用户查看网格的该部分时拉出显示给用户的行。

编辑

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

父 1,空,空
父 1、子 1、110
父 1、子 12、12
父 2,空,空
父 2、子 21、23
父 2,子 22 ,20
Leaf1,空,20
Leaf2,空,34

这看起来像你需要某种left join和 a count,并有潜在的union all投入。

于 2010-08-31T11:31:41.767 回答
1

慢的不是 foreach,而是添加和渲染新项目。

添加开始更新/结束更新:

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();
于 2010-08-31T11:51:29.813 回答
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));
}
于 2010-08-31T13:58:06.653 回答
-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 的方式

于 2010-08-31T11:15:46.607 回答