Skip to content
Coding

Object List Compare:IntersectBy 和 Foreach 比較

Object List Compare:IntersectBy 和 Foreach 比較
IntersectBy() 底層的實作

目錄

  • 一個條件: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

Source