对于List <object>为什么?</object>,find和findindex痛苦缓慢

时间:2012-02-17 15:40:48

标签: c# list find

我正在使用密集使用List的项目,我尝试通过名称(即对象的成员)查找对象。

我的代码在没有使用单个for-next循环(函数find1)进行搜索的情况下工作但我发现使用内置的find找到它是可能的,并且代码可以工作。但是,感觉有点慢。所以,我做了一个测试速度的项目:

我有下一个代码

    public List<MyObject> varbig = new List<MyObject>();
    public Dictionary<string,string> myDictionary=new Dictionary<string, string>();
    public Form1() {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e) {
        myDictionary.Clear();
        varbig.Clear();

        for (int i = 0; i < 5000; i++) {
            varbig.Add(new MyObject("name" + i.ToString(),"value"+i.ToString()));
            myDictionary.Add("name" + i.ToString(), i.ToString());
        }
        // first test
        var start1 = Environment.TickCount;
        for (int i = 0; i < 3000; i++) {
            var ss=find1("name499");
        }
        var end1 = Environment.TickCount;
        Console.WriteLine("time  1 :" + (end1 - start1));
        // second test
        var start2 = Environment.TickCount;
        for (int i = 0; i < 3000; i++) {
            var ss=find2("name499");
        }
        var end2 = Environment.TickCount;
        Console.WriteLine("time  2 :" + (end2 - start2));
        // third test
        var start3 = Environment.TickCount;
        for (int i = 0; i < 3000; i++) {
            var ss = find3("name499");
        }
        var end3 = Environment.TickCount;
        Console.WriteLine("time  3 :" + (end3 - start3));

        // first test b
        var start1b = Environment.TickCount;
        for (int i = 0; i < 3000; i++) {
            var ss=find1("name4999");
        }
        var end1b = Environment.TickCount;
        Console.WriteLine("timeb 1 :" + (end1b - start1b));
        // second test
        var start2b = Environment.TickCount;
        for (int i = 0; i < 3000; i++) {
            var ss=find2("name4999");
        }
        var end2b = Environment.TickCount;
        Console.WriteLine("timeb 2 :" + (end2b - start2b));
        // third test
        var start3b = Environment.TickCount;
        for (int i = 0; i < 3000; i++) {
            var ss = find3("name4999");
        }
        var end3b = Environment.TickCount;
        Console.WriteLine("timeb 3 :" + (end3b - start3b));

    }

    public int find1(string name) {
        for (int i = 0; i < varbig.Count; i++) {
            if(varbig[i].Name == name) {
                return i;
            }
        }
        return -1;
    }

    public int find2(string name) {
        int idx = varbig.FindIndex(tmpvar => Name == name);
        return idx;
    }
    public int find3(string name) {
        var ss=myDictionary[name];
        return int.Parse(ss);
    }
}

我使用下一个对象

public class MyObject {
    private string _name = "";
    private string _value = "";
    public MyObject() {}

    public MyObject(string name, string value) {
        _name = name;
        _value = value;
    }

    public string Name {
        get { return _name; }
        set { _name = value; }
    }

    public string Value {
        get { return _value; }
        set { _value = value; }
    }
}

它主要做下一件事: 我创建了一个包含5000个元素的数组。

时间1 =使用简单的for-next搜索第499个对象(索引)。

时间2 =使用内置函数find of List

搜索第499个

时间3 =它使用字典搜索第499个元素。

Timeb 1,timeb 2和timeb 3执行相同操作但尝试搜索第4999个元素而不是第499个元素。

我跑了几次:

  • 时间1:141
  • 时间2:1248
  • 时间3:0
  • timeb 1:811
  • timeb 2:1170
  • timeb 3:0

  • 时间1:109

  • 时间2:1170
  • 时间3:0
  • timeb 1:796
  • timeb 2:1170
  • timeb 3:0

(小而快)

而且,令我惊讶的是,功能 findindex 的构建速度非常慢(在某些情况下,速度接近10倍。而且,字典方法几乎是即时的。

我的问题是,为什么?是因为谓词吗?

4 个答案:

答案 0 :(得分:2)

问题出在这一行:

int idx = varbig.FindIndex(tmpvar => Name == name);

Name == name错了,您应该改为tmpvar.Name == name

在您的代码中,您将name参数与表单的Name属性进行比较;它们显然是不同的,因此该方法始终检查整个列表,而不是在找到搜索值时停止。事实上,正如你可以看到的那样,find2()花费的时间基本上是相等的。

关于字典,它显然比其他方法更快,因为字典是专门为提供快速键控访问而构建的内存结构。

事实上,它们的时间复杂度接近O(1),而循环列表的时间复杂度等于O(n)

答案 1 :(得分:1)

  • Find1使用简单的for(i = 0 to count)方法
  • Find2使用内置的Find方法(上面正好是find1),除了你已经传递了一个谓词,我相信这会减慢它的速度。
  • Find3使用字典,我认为是没有任何计时器的最快,因为字典使用哈希表下有一个0(1)查找(持续时间)

答案 2 :(得分:1)

代码中存在错误 - find2方法使用Form.Name进行比较,而不是使用集合对象名称。它应该是这样的:

public int find2(string name) {
    return varbig.FindIndex((obj) => obj.Name == name);
}

不使用Form.Name的结果更加一致:

time  1 :54
time  2 :50
time  3 :0
timeb  1 :438
timeb  2 :506
timeb  3 :0

答案 3 :(得分:0)

您无需放入for循环即可在find2中进行搜索...

直接调用find2,结果将为0。