我试图找到一种禁用的方法来设置通用列表中每个项目的特定属性。
基本上,要求是迭代项目列表并将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,但这只是我的头脑......我只看到代表们产生更少的线条,无论这意味着什么。
答案 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 )