2009-09-16 44 views
1

我正在试图找到禁食的方式来设置通用列表中每个项目的特定属性。C#每个列表项目的性能设置值

基本上,需求是迭代项目列表并将IsHit属性重置为FALSE。之后只有第二个“hit”列表中的项目应设置为TRUE。

我第一次尝试是这样的:

listItems.ForEach(delegate(Item i) { i.IsHit = false; }); 

foreach (int hitIndex in hits) 
{ 
    listItems[hitIndex - 1].IsHit = true; 
} 

注:点击率是1为主,项目列表是基于0。

然后我试图提高速度以及与此想出了:

for (int i = 0; i < listItems.Count; i++) 
{ 
    bool hit = false; 
    for (int j = 0; j < hits.Count; j++) 
    { 
     if (i == hits[j] - 1) 
     { 
      hit = true; 
      hits.RemoveAt(j); 
      break; 
     } 
    } 

    if (hit) 
    { 
     this.listItems[i].IsHit = true; 
    } 
    else 
    { 
     this.listItems[i].IsHit = false; 
    } 
} 

我知道这是一个微型的优化,但它确实是时间敏感的代码,所以它才有意义,以提高这些代码超出了可读性...当然只是为了好玩;-)

不幸的是,我真的没有看到任何改进代码的方法。但我可能错过了一些东西。



由于

PS:代码在C#/ .NET 2.0是优选的。


我结束了切换到Eamon Nerbonne解决方案。但后来我发现我的基准测试中有些奇怪。

委托:

listItems.ForEach(delegate(Item i) { i.IsHit = false; }); 

快于:

foreach (Item i in listItems) 
{ 
    i.IsHit = false; 
} 

这怎么可能?

我试着看IL,但那只是我头上的方式......我只看到代表的结果行数较少,无论如何。

+0

有没有机会将“命中”列表更改为哈希表?通过去除第二个for循环将大大提高性能。 – 2009-09-16 08:20:39

回答

2

嵌套的循环是矫枉过正,特别是“remove”调用本身代表了另一个for-loop。总而言之,您的第二个优化版本比第一个解决方案的时间复杂性要差,特别是当有很多点击时。

最快的溶液可能是以下内容:

foreach(var item in listItems) 
    item.IsHit = false; 
foreach (int hitIndex in hits) 
    listItems[hitIndex - 1].IsHit = true; 

这避免了低效率的嵌套for循环,并且其避免了基于.ForEach方法(委托其是精细方法的开销,但不在性能关键代码中)。它涉及更频繁地设置IsHit,但大多数属性设置器都是微不足道的,因此这可能不是瓶颈。在任何情况下,快速的微型基准测试都可以作为良好的健全性检查。

只有IsHit是真正的慢,下面会更快:

bool[] isHit = new bool[listItems.Count]; //default:false. 
//BitArray isHit = new BitArray(listItems.Count); 
//BitArray is potentially faster for very large lists. 
foreach (int hitIndex in hits) 
    isHit [hitIndex - 1] = true; 
for(int i=0; i < listItems.Count; i++) 
    listItems[i].IsHit = isHit[i]; 

最后,可以考虑使用一个数组,而不是一个List<>。如果您可以避免需要类型的插入/移除方法,则阵列通常会更快。

var关键字是C#3.5,但可以在.NET 2.0中使用(新语言功能通常不需要较新的库版本 - 只是它们对于那些较新的库最有用)。当然,您知道List<>专用的类型,并且可以明确指定它。

+1

关于OP第二个版本复杂性的小问题:Remove调用将精确地遍历那些由*显式内部for循环遍历的命中元素,因此该解决方案的整体复杂性按照listItems的顺序进行。计数'×'点击。计数' – 2009-09-16 10:00:40

3

你可以把你的第二个列表的项目放在字典中吗? 如果是这样,你可以这样做:

for(int i = 0; i < firstList.Count; i++) 
{ 
    firstList[i].IsHit = false; 

    if(secondList.Contains (firstList[i].Id)) 
    { 
     secondList.Remove (firstList[i].Id); 
     firstList[i].IsHit = true; 
    } 
} 

凡secondList是一个字典offcourse。

通过将词汇表中的项目放入词典中,您可以使用O(1)操作检查项目是否包含在该列表中。 在上面的代码中,我使用某种Item的唯一标识符作为字典中的Key。

+3

而不是字典,你可以使用HashSet 。此外,如果您确定所有匹配都将被“使用”,则无需从字典/集合中删除匹配 - 只需在循环后清空集合即可。 – maciejkow 2009-09-16 08:45:07

+0

是的,你是对的HashSet集合。我有时忘记它的存在,但:o。 关于从集或字典中删除项目:我刚刚完成它,因为我看到topicstarter在他的示例代码中也是这样做的。也许他还有另一个原因,但是在使用集合或字典时,确实没有必要这样做。 – 2009-09-16 08:49:34

+0

'HashSet <>'和'Dictionary <>'比普通旧数组慢很多 - 因为你处理的是密集整数索引,所以在这里,哈希集和字典没有任何有意义的附加功能。 – 2009-09-16 09:57:22

0

也许你可以排序的命中收集和执行二进制搜索,那么你将是O(N日志 N),而不是为O(n )

相关问题