Object List Compare:IntersectBy 和 Foreach 比較
目錄
- 一個條件:IntersectBy 使用
- IntersectBy 和 Foreach 花費時間比較
IntersectBy / ExpectBy
一般使用上免不了需要做兩個陣列的比較,簡單一點的情況可以直接使用 Intersect() 即可,但常常都會是 Object List 的狀況比較棘手,這時候可以使用 IntersectBy()。
首先要來製造出一堆物件:
public class LetterService
{
private static readonly char[] chars = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
public List<Letter> Generate(int count)
{
var letters = new List<Letter>();
var random = new Random();
for (var i = 0; i < count; i++)
{
var index = random.Next(chars.Length);
var letter = chars[index];
var isUpper = char.IsUpper(letter);
letters.Add(new Letter()
{
Name = letter,
Id = i + 1,
Type = isUpper ? EnumLetter.Upper : EnumLetter.Lower
});
}
return letters;
}
}然後進行使用:
var letterService = new LetterService();
var letters1 = letterService.Generate(15);
var letters2 = letterService.Generate(15);
// 如果 1 和 2 中有 Letter 的 Name 相同,就選取 1 的 Letter
var intersectBy1 = letters1.IntersectBy(letters2.Select(l => l.Name), l => l.Name).ToList();
// 如果 1 和 2 中有 Letter 的 Name 相同,就選取 2 的 Letter
var intersectBy2 = letters2.IntersectBy(letters1.Select(l => l.Name), l => l.Name).ToList();要注意 A.IntersectBy(B) 和 B.IntersectBy(A) 的差異,兩者都會去找指定的條件是否相同,差異在於找到相同條件的物件之後,A.IntersectBy(B) 是 Select 出 List<A>,B.IntersectBy(A) 則是 List<B>。
ar letters1 = new List<Letter>()
{
new()
{
Name = "A",
Type = EnumLetter.Upper,
Id = 1
},
new()
{
Name = "b",
Type = EnumLetter.Lower,
Id = 2
},
new()
{
Name = "C",
Type = EnumLetter.Upper,
Id = 3
}
};
var letters2 = new List<Letter>()
{
new()
{
Name = "a",
Type = EnumLetter.Lower,
Id = 1
},
new()
{
Name = "B",
Type = EnumLetter.Upper,
Id = 2
},
new()
{
Name = "C",
Type = EnumLetter.Upper,
Id = 1
},
};
// Name = C, Type = Upper, Id = 3
var intersectBy1 = letters1.IntersectBy(letters2.Select(l => l.Name), l => l.Name).ToList();
// Name = C, Type = Upper, Id = 1
var intersectBy2 = letters2.IntersectBy(letters1.Select(l => l.Name), l => l.Name).ToList();IntersectBy V.S. Foreach

IntersectBy() 底層的實作既然有 Foreach 為甚麼還需要 IntersectBy()?先不論其他的因素,單看 yeild return 理論上會比較快,所以實際來測試看看:
using System.Diagnostics;
var compareService = new CompareService();
compareService.Do(50);
compareService.Do(500);
compareService.Do(5000);
compareService.Do(50000);
public class CompareService
{
public void Do(int count)
{
var letterService = new LetterService();
var letters1 = letterService.Generate(count);
var letters2 = letterService.Generate(count);
Console.WriteLine($"----------比較 {count} 筆的差異----------");
var stopwatch = new Stopwatch();
stopwatch.Reset();
stopwatch.Start();
var intersect = letters1.IntersectBy(letters2.Select(l => l.Name), l => l.Name).ToList();
var intersectTime = stopwatch.ElapsedMilliseconds;
Console.WriteLine($"使用 IntersectBy 總共花費 {intersectTime} 豪秒");
var intersectForeach = new List<Letter>();
stopwatch.Reset();
stopwatch.Start();
foreach (var letter1 in letters1)
{
foreach (var letter2 in letters2)
{
if (letter1.Name == letter2.Name)
{
if (intersectForeach.Find(letter => letter.Name == letter1.Name) == null)
intersectForeach.Add(letter1);
}
}
}
var intersectForeachTime = stopwatch.ElapsedMilliseconds;
Console.WriteLine($"使用 Foreach 總共花費 {intersectForeachTime} 豪秒");
}
}實際執行的結果如下:

可以看到量少的時候其實使用哪一種方法都差不多,但當數量到萬的時候落差就出來了,的確是 IntersectBy() 比較快。
References
- stackoverflow-Comparing two lists with multiple conditions
- 黑暗執行緒-善用 yield return 省時省 CPU 省 RAM,打造高效率程式