> ## Content Index
> Fetch the complete content index at: https://blog.anthea.day/llms.txt
> Use this file to discover other available public pages before exploring further.

# Object List Compare：IntersectBy 和 Foreach 比較
- URL: https://blog.anthea.day/dotnet-object-list-compare/
- Published: 2022-10-15T18:15:36.000Z
- Updated: 2026-11-07T14:48:49.000Z
- Author: Anthea / 芫荽
- Tags: #Migrated-1792241843742, #Import 2026-10-17 12:57, Coding, .NET

#### 目錄

- 一個條件：IntersectBy 使用
- IntersectBy 和 Foreach 花費時間比較

---

### IntersectBy / ExpectBy

一般使用上免不了需要做兩個陣列的比較，簡單一點的情況可以直接使用 `Intersect()` 即可，但常常都會是 Object List 的狀況比較棘手，這時候可以使用 `IntersectBy()`。

首先要來製造出一堆物件：

```C#
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;
    }
}
```

然後進行使用：

```C#
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>`。

```C#
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

![](https://cdn-images-1.medium.com/max/800/1*eWrDBeaFUqHTLYmnx_gb1A.png)

`IntersectBy()` 底層的實作

既然有 `Foreach` 為甚麼還需要 `IntersectBy()`？先不論其他的因素，單看 `yeild return` [理論上會比較快](https://blog.darkthread.net/blog/yield-return/?ref=blog.anthea.day)，所以實際來測試看看：

```C#
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} 豪秒");
    }
}
```

實際執行的結果如下：

![](https://cdn-images-1.medium.com/max/800/1*vml1cdoa7HPSSEW7gRzrYw.png)

可以看到量少的時候其實使用哪一種方法都差不多，但當數量到萬的時候落差就出來了，的確是 `IntersectBy()` 比較快。

---

#### References

- [stackoverflow－Comparing two lists with multiple conditions](https://stackoverflow.com/questions/37397020/comparing-two-lists-with-multiple-conditions?ref=blog.anthea.day)
- [黑暗執行緒－善用 yield return 省時省 CPU 省 RAM，打造高效率程式](https://blog.darkthread.net/blog/yield-return/?ref=blog.anthea.day)

#### Source

- [完整程式碼](https://github.com/anthea-wu/medium-2a8b64e9d9f0?ref=blog.anthea.day)