C#每个列表项的性能设置值

时间:2009-09-16 08:08:45

标签: c# performance search list

我试图找到一种禁用的方法来设置通用列表中每个项目的特定属性。

基本上,要求是迭代项目列表并将IsHit属性重置为FALSE。之后,只有第二个“命中”列表中的项目应设置为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,但这只是我的头脑......我只看到代表们产生更少的线条,无论这意味着什么。

3 个答案:

答案 0 :(得分: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是一个词典偏离。

通过将histlist的项目放在Dictionary中,如果项目包含在该列表中,则可以使用O(1)操作进行检查。 在上面的代码中,我使用Item的某种唯一标识符作为字典中的Key。

答案 1 :(得分:2)

嵌套的for循环是过度的,特别是“删除”调用本身代表另一个for循环。总而言之,您的第二个优化版本比第一个解决方案的时间复杂度更差,特别是当有很多点击时。

最快的解决方案可能如下:

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<>。如果您可以避免使用List<>类型的插入/删除方法,则数组通常会更快。

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

答案 2 :(得分:0)

您可以对命中集合进行排序并执行二分查找,然后您将是O(n log 2 n)而不是O(n 2