Find first element matching condition in Swift arr

2019-02-02 20:25发布

I would like to find the first EKSource of type EKSourceType.Local with a "single"-line expression in Swift. Here is what I currently have:

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

Is there a better way of doing this (such as without mapping and/or with a generic version of find)?

6条回答
smile是对你的礼貌
2楼-- · 2019-02-02 20:58

I don't understand why you're using map at all. Why not use filter? You will then end up with all the local sources, but in actual fact there will probably be only one, or none, and you can readily find out by asking for the first one (it will be nil if there isn't one):

let local = eventStore.sources.filter{$0.sourceType == .Local}.first
查看更多
祖国的老花朵
3楼-- · 2019-02-02 20:58

Swift 4 solution that also handles the situation when there are no elements in your array that match your condition:

if let firstMatch = yourArray.first{$0.id == lookupId} {
  print("found it: \(firstMatch)")
} else {
  print("nothing found :(")
}
查看更多
孤傲高冷的网名
4楼-- · 2019-02-02 20:59

Alternatively in Swift3 you could use:

let local = eventStore.sources.first(where: {$0.sourceType == .Local}) 
查看更多
淡お忘
5楼-- · 2019-02-02 21:01

Let's try something more functional:

let arr = [0,1,2,3]
let result = arr.lazy.map{print("                                                                    
查看更多
劳资没心,怎么记你
6楼-- · 2019-02-02 21:14

There's a version of indexOf that takes a predicate closure - use it to find the index of the first local source (if it exists), and then use that index on eventStore.sources:

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

Alternately, you could add a generic find method via an extension on 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 })

(Why isn't this there already?)

查看更多
狗以群分
7楼-- · 2019-02-02 21:15

For Swift 3 you'll need to make a few small changes to Nate's answer above. Here's the Swift 3 version:

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
    }
}

Changes: SequenceType > Sequence, Self.Generator.Element > Iterator.Element

查看更多
登录 后发表回答