为什么不是';t使用FindIndex(),并比FindAll()更快地从迭代中提前返回

本文关键字:迭代 返回 FindAll 为什么不 FindIndex 使用 并比 | 更新日期: 2023-09-27 18:28:23

我需要在列表项上测试的匹配条件非常耗时。此外,我知道该条件将匹配不超过3项的列表。

因此,检查所有列表项可能不是最好的主意;然而,当我尝试最多使用FindFindex()方法3次时,测试比我使用FindAll()Where()的情况花费更多。

我如何加快这种方法的速度,或者最多能更快地找到三个匹配?

| #  Method            Time (sec)
| -------------------------------
| 1   Find (one-by-one)   42.37
| 2   FindAll             30.17
| 3   Where               30.53

方法#1:

{
    int index;
    Predicate<T> predicate = t =>
        {
            ...
        };
    index = myCollection.FindIndex(predicate);
    if (index != -1)
    {
        T t1 = myCollection[index];
        myCollection.RemoveAt(index);
        index = myCollection.FindIndex(predicate);
        if (index != -1)
        {
            T t2 = myCollection[index];
            myCollection.RemoveAt(index);
            index = myCollection.FindIndex(predicate);
            if (index != -1)
            {
                T t3 = myCollection[index];
                return new T[] { t1, t2, t3 };
            }
            else
            {
                return new T[] { t1, t2 };
            }
        }
        else
        {
            return new T[] { t1 };
        }
    }
    else
    {
        return new T[] { };
    }
}

方法#2:

{
    return myCollection.FindAll(t =>
    {
        ...
    }).ToArray();
}

方法#3:

{
    return myCollection.Where(t =>
    {
        ...
    }).ToArray();
}

编辑:修改方法#1:

{
    int index;
    Predicate<T> predicate = t =>
        {
            ...
        };
    index = myCollection.FindIndex(predicate);
    if (index != -1)
    {
        T t1 = myCollection[index];
        index = myCollection.FindIndex(index + 1, predicate);
        if (index != -1)
        {
            T t2 = myCollection[index];
            index = myCollection.FindIndex(index + 1, predicate);
            if (index != -1)
            {
                T t3 = myCollection[index];
                return new T[] { t1, t2, t3 };
            }
            else
            {
                return new T[] { t1, t2 };
            }
        }
        else
        {
            return new T[] { t1 };
        }
    }
    else
    {
        return new T[] { };
    }
}

为什么不是';t使用FindIndex(),并比FindAll()更快地从迭代中提前返回

您的方法较慢,因为它在整个集合上迭代三次,而且您执行的删除操作也会受到惩罚(根据MSDN,为"O(n),其中n是(计数-索引)")。

您可以通过调用FindIndex(int, predicate)重载来避免这两种情况,其中int在迭代源集合时终止起始位置。

因此,更换出现这种情况的两个位置:

myCollection.RemoveAt(index);
index = myCollection.FindIndex(predicate);

有了这个:

index = myCollection.FindIndex(index + 1, predicate) 

只要使用List,就没有办法,只能在集合中迭代。你可以修改#3如下:

return myCollection.Where(...).Take(3).ToArray();

ToArray将开始迭代,take 3将限制迭代在3个结果之后停止。这与您的#1(修改后的)示例实际上是一样的。

编辑:

以下是关于Take工作行为的Linqpad测试程序:

void Main()
{
    var list = new List<Something>();
    for(int i=0; i<100; i++)
        list.Add(new Something { Value = i });
    var result = list.Where(p => p.Value < 50).Take(3);
    result.Count().Dump();
}
public class Something
{
    private int _value;
    public int Value 
    {
        get { _value.Dump(); return _value; }
        set { _value = value; }
    }
}

测试结果:

0
1
2
3

最后一个是集合计数,只枚举了3项。