为什么不使用FindIndex()并以比FindAll()更快的迭代时间返回?

时间:2015-12-30 01:23:18

标签: c# list

我需要在列表项上测试的匹配条件非常耗时。而且,我知道条件将匹配不超过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[] { };
    }
}

2 个答案:

答案 0 :(得分:6)

你的方式较慢,因为它遍历整个集合三次,并且因为你执行删除操作也会受到惩罚(“O(n),其中n是(Count - index)” according to MSDN)。

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

因此,请更换发生这种情况的地方:

myCollection.RemoveAt(index);

index = myCollection.FindIndex(predicate);

有了这个:

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

答案 1 :(得分:2)

只要使用了List,就没有办法,只能迭代集合。您可以修改#3,如下所示:

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

ToArray将开始迭代,并且3将限制迭代在3个结果后停止。对于#1(修改过的)示例,这几乎是一回事。

编辑:

以下是关于Take&#39的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个项目。