查找一个对象 在对象列表中的位置是日常项目开发过程中最最常用的。大慨总结了一下,有3个常用的方法。

  

1
2
3
4
5
6
7
8
public class Test
{
        public string Name
        {
            get;
            set;
        }
}

 

一、最最常用的 依次循环查找法

1
2
3
4
5
6
7
8
9
10
11
12
private int LoopMethod()
  {
      for (int i =0; i < testList.Count; i++)
      {
          Test t = testList[i];
          if (t.Name.Equals(this.findName))
          {
              return i;
          }
      }
      return -1;
  }



 二、List.IndexOf 方法

1
2
3
4
5
6
7
8
9
private int IndexOfMethod()
{
    Test find = new Test()
    {
        Name = this.findName
    };
    int i = testList.IndexOf(find);
    return i;
}

 

   同时需要将 Test.Equals方法进行重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Test
{
    public string Name
    {
        get;
        set;
    }
 
    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
 
    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }
 
        if (!(obj is Test)) return false;
 
        return string.Equals(this.Name, (obj as Test).Name);
    }
}

 

 三、Linq方法

  

1
2
3
4
5
private int LinqMethod()
{
    int index = testList.FindIndex(test => test.Name.Equals(this.findName));
    return index;
}

  

 

 

 总结:

  经过一些代码测试发现(第一种、第二种、第三种):

     第一种方法的查询速度最快,再次是 Linq查询方法,再就是List.IndexOf方法

     测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
List<Test> testList;
string findName = "";
testList = new List<Test>();
for (int i = 0; i < 10000; i++ )
{
    string name = Guid.NewGuid().ToString();
    if (i == 9998)
    {
        findName = name;
    }
    Test t = new Test()
    {
        Name = name
    };
    testList.Add(t);
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
int index = -1;
for (int k = 0; k < 100; k++)
{
    index = LoopMethod();
}
watch.Stop();
Console.WriteLine("LoopMethod: " + index.ToString() + ": " + watch.ElapsedMilliseconds.ToString());
 
System.Diagnostics.Stopwatch watchIndex = new System.Diagnostics.Stopwatch();
watchIndex.Start();
for (int k = 0; k < 100; k++)
{
    index = IndexOfMethod();
}
watchIndex.Stop();
Console.WriteLine("IndexOfMethod : " + index.ToString() + ": " + watchIndex.ElapsedMilliseconds.ToString());
 
System.Diagnostics.Stopwatch watchLinq = new System.Diagnostics.Stopwatch();
watchLinq.Start();
int res = -1;
for (int k = 0; k < 100; k++)
{
    res = LinqMethod();
}
watchLinq.Stop();
Console.WriteLine("LinqMethod : " + res.ToString() + ": " + watchLinq.ElapsedMilliseconds.ToString());

 

 

运行结果:

  LoopMethod: 9998: 99
     IndexOfMethod : 9998: 157
     LinqMethod : 9998: 114

 经简单分析:

  LoopMethod 耗时主要在依次循环中

     IndexOfMethod 耗时主要在 Equals 方法中。

     Linq方法 耗时主要在委托中

经过反编译发现:这3种方法的原理都是依次查询。

  IndexOf方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public int IndexOf(T item)
{
    return Array.IndexOf<T>(this._items, item, 0, this._size);
}
 
  
public static int IndexOf<T>(T[] array, T value, int startIndex, int count)
{
    if (array == null)
    {
        throw new ArgumentNullException("array");
    }
    if ((startIndex < 0) || (startIndex > array.Length))
    {
        throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
    }
    if ((count < 0) || (count > (array.Length - startIndex)))
    {
        throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
    }
    return EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count);
}
 
  
internal virtual int IndexOf(T[] array, T value, int startIndex, int count)
{
    int num = startIndex + count;
    for (int i = startIndex; i < num; i++)
    {
        if (this.Equals(array[i], value))
        {
            return i;
        }
    }
    return -1;
}

 

      Linq 方法核心:  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public int FindIndex(Predicate<T> match)
{
    return this.FindIndex(0, this._size, match);
}
 
  
 
 public int FindIndex(int startIndex, int count, Predicate<T> match)
{
    if (startIndex > this._size)
    {
        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
    }
    if ((count < 0) || (startIndex > (this._size - count)))
    {
        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count);
    }
    if (match == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
    }
    int num = startIndex + count;
    for (int i = startIndex; i < num; i++)
    {
        if (match(this._items[i]))
        {
            return i;
        }
    }
    return -1;
}