find和findindex对于List<;对象>;为什么?
本文关键字:对象 gt 为什么 lt 对于 List find findindex | 更新日期: 2023-09-27 18:24:55
我正在一个密集使用List的项目中工作,我试图通过名称(即对象的成员)找到对象。
我的代码在没有使用单个for next循环(函数find1)进行搜索的情况下工作了,但我发现使用内置的find 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=使用simple for next搜索第499个对象(索引)。
时间2=使用List的内置函数find搜索第499个
时间3=使用字典搜索第499个元素。
时间b1、时间b2和时间b3执行相同的操作,但尝试搜索第4999个元素而不是第499个元素。
我跑了几次:
- 时间1:141
- 时间2:1248
- 时间3:0
- 时间b 1:811
- 时间b 2:1170
时间b 3:0
时间1:109
- 时间2:1170
- 时间3:0
- 时间b 1:796
- 时间b 2:1170
- 时间b 3:0
(先小后快)
而且,令我惊讶的是,内置函数findindex慢得离谱(在某些情况下,慢了近10倍。此外,字典方法几乎是即时的。
我的问题是,为什么?。是因为谓词吗?。
问题出在这一行:
int idx = varbig.FindIndex(tmpvar => Name == name);
Name == name
是错误的,您应该改为编写tmpvar.Name == name
。
在您的代码中,您正在将name
参数与表单的Name
属性进行比较;它们明显不同,因此该方法总是检查整个列表,而不是在找到搜索值时停止。事实上,正如你从数字中看到的,find2()
花费的时间基本上总是相等的。
关于字典,它显然比其他方法更快,因为字典是专门为提供快速键控访问而构建的内存结构。
事实上,它们的时间复杂度接近O(1)
,而循环列表时,时间复杂度等于O(n)
。
- Find1正在使用一个简单的for(i=0计数)方法
- Find2使用内置的Find方法(正是上面的find1),只是您传递了一个谓词,我认为这会减慢它的速度
- 我认为使用字典的Find3在没有任何定时器的情况下是最快的,因为字典在封面下使用哈希表,它有0(1)的查找(连续时间)
您的代码中存在错误-find2
方法使用Form.Name进行比较,而不是您的集合对象名称。它应该是这样的:
public int find2(string name) {
return varbig.FindIndex((obj) => obj.Name == name);
}
不使用表单的结果。名称更一致:
time 1 :54
time 2 :50
time 3 :0
timeb 1 :438
timeb 2 :506
timeb 3 :0
在find2
中搜索不需要放入for
循环。。。
直接调用find2
,结果为0。