Найти первое условие соответствия элемента в массиве Swift (например, EKSource)

Я хотел бы найти первый EKSource типа EKSourceType.Local с "одиночным" строчным выражением в Swift. Вот что у меня сейчас есть:

let eventSourceForLocal = 
    eventStore.sources[eventStore.sources.map({ $0.sourceType })
        .indexOf(EKSourceType.Local)!]

Есть ли лучший способ сделать это (например, без отображения и / или с общей версией find)?

6 ответов

Решение

Там есть версия indexOf это требует закрытия предиката - используйте его, чтобы найти индекс первого локального источника (если он существует), а затем используйте этот индекс на eventStore.sources:

if let index = eventStore.sources.indexOf({ $0.sourceType == .Local }) {
    let eventSourceForLocal = eventStore.sources[index]
}

В качестве альтернативы, вы можете добавить общий find метод через расширение на SequenceType:

extension SequenceType {
    func find(@noescape predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Self.Generator.Element? {
        for element in self {
            if try predicate(element) {
                return element
            }
        }
        return nil
    }
}

let eventSourceForLocal = eventStore.sources.find({ $0.sourceType == .Local })

(Почему это уже не там?)

В качестве альтернативы в Swift3 вы можете использовать:

let local = eventStore.sources.first(where: {$0.sourceType == .Local}) 

Я не понимаю, почему вы используете map совсем. Почему бы не использовать filter? Затем вы получите все локальные источники, но на самом деле, вероятно, будет только один, или ни одного, и вы можете легко узнать, запросив первый (это будет nil если его нет)

let local = eventStore.sources.filter{$0.sourceType == .Local}.first

РешениеSwift 4, которое также обрабатывает ситуацию, когда в вашем массиве нет элементов, соответствующих вашему условию:

if let firstMatch = yourArray.first{$0.id == lookupId} {
  print("found it: \(firstMatch)")
} else {
  print("nothing found :(")
}

Swift 5 Если вы хотите узнать из массива модели, укажите $0.keyTofound, иначе используйте $0

if let index = listArray.firstIndex(where: { $0.id == lookupId }) {
     print("Found at \(index)")
} else {
     print("Not found")
 }

Давайте попробуем что-то более функциональное:

let arr = [0,1,2,3]
let result = arr.lazy.map{print("");return $0}.first(where: {$0 == 2})
print(result)//3x  then 2

Что крутого в этом?
Вы получаете доступ к элементу или я во время поиска. И это функционально.

Для Swift 3 вам нужно внести несколько небольших изменений в ответ Нейта выше. Вот версия Swift 3:

public extension Sequence {
    func find(predicate: (Iterator.Element) throws -> Bool) rethrows -> Iterator.Element? {
        for element in self {
            if try predicate(element) {
                return element
            }
        }
        return nil
    }
}

Изменения: SequenceType > Sequence, Self.Generator.Element > Iterator.Element

Другие вопросы по тегам