---
# System prepended metadata

title: 'Combine-如何快速搜尋元素？ -first(where:) last(where:)'

---

# Combine-如何快速搜尋元素？ -first(where:) last(where:)
## Overview

```swift
  let numbers = (1...10).publisher
  numbers
    .print("numbers")
    .first(where: { $0 % 3 == 0 })
    .sink{
        print($0)
    }
    .store(in: &subscriptions)
```
從這個結果來看，會回傳第一個可以被3整除的元素。
```
3
```

```swift
let numbers = (1...10).publisher
  numbers
    .print("numbers")
    .last(where: { $0 % 3 == 0 })
    .sink{
        print($0)
    }
    .store(in: &subscriptions)
```

從這個結果來看，會回傳最後可以被3整除的元素。
```
9
```

這邊我們會認識 first(where:) 以及 last(where:)這兩個 operater。其實可以很簡單地從文字上認識他。first 就是從第一個元素開始往後搜尋；last 反之。可以關注的是後面的 where 是一個回傳 Bool 的閉包，當他回傳 true 時代表找到目標元素，找到目標元素會立刻終止搜尋。False 則會繼續搜尋。
## first(where:)
first 從前面的元素開始巡訪，從where 閉包當作尋找條件。
```swift=
  let numbers = (1...10).publisher
  numbers
    .print()
    .first(where: { item in
        print(item)
        return item % 3 == 0
    })
    .sink{
        print("find \($0)")
    }
    .store(in: &subscriptions)
```
```swift=
receive subscription: (1...10)
request unlimited
receive value: (1)
1
receive value: (2)
2
receive value: (3)
3
receive cancel
find 3
```
從剛剛實驗得圖得知，當元素找到後，不會繼續尋訪，而是立刻終止。
![](https://hackmd.io/_uploads/BJr8G1nfa.png)

## 發出 complete 之後才會運作。
因為operator無法知道publisher是否會在後續發出符合條件的值，因此operator必須了解完整的publisher範圍，才能確定滿足最後一個項目。

```swift=
    let numbers = PassthroughSubject<Int, Never>()
      numbers
        .last(where: { $0 % 2 == 0 })
        .sink(receiveCompletion: { _ in print("Completed") },
              receiveValue: { print($0) })
        .store(in: &subscriptions)
      numbers.send(1)
      numbers.send(2)
      numbers.send(3)
      numbers.send(4)
      numbers.send(5)
    numbers.send(completion: .finished)
```

```swift=
4
Completed
```