Swift是否具有像Any或All这样的短程高阶函数?

时间:2017-06-02 20:41:59

标签: swift higher-order-functions short-circuiting

我了解Swift的高阶函数,如Map,Filter,Reduce和FlatMap,但我不知道任何类似的' All'或者'任何'返回一个布尔值,在枚举结果的同时在阳性测试中发生短路。

例如,假设您拥有10,000个对象的集合,每个对象都有一个名为isFulfilled的属性,并且您希望查看该集合中是否有isFulfilled设置为false。在C#中,您可以使用myObjects.Any(obj -> !obj.isFulfilled),当该条件被命中时,它会使枚举的其余部分短路并立即返回true

Swift中有没有这样的东西?

3 个答案:

答案 0 :(得分:5)

Sequence(特别是CollectionArray)有一个(短路)contains(where:)方法,将布尔谓词作为参数。例如,

if array.contains(where: { $0 % 2 == 0 })

检查数组是否包含任何偶数。

没有"所有"方法,但您也可以使用contains() 通过否定谓词和结果。例如,

if !array.contains(where: { $0 % 2 != 0 })

检查数组中所有数字是否均匀。当然,您可以定义自定义扩展方法:

extension Sequence {
    func allSatisfy(_ predicate: (Iterator.Element) -> Bool) -> Bool {
        return !contains(where: { !predicate($0) } )
    }
}

如果你想允许"投掷"谓语的方式与 contains方法然后将其定义为

extension Sequence {
    func allSatisfy(_ predicate: (Iterator.Element) throws -> Bool) rethrows -> Bool {
        return try !contains(where: { try !predicate($0) } )
    }
}

更新:正如James Shapiro正确注意到的那样, Swift 4.2 中的allSatisfy类型添加了Sequence方法(目前处于测试阶段) ),见

(需要最近的4.2开发者快照。)

答案 1 :(得分:3)

你可以在Swift中做的另一件事就是"短路"在这种情况下,使用集合的lazy属性,这会将您的实现更改为以下内容:

myObjects.lazy.filter({ !$0.isFulfilled }).first != nil

它与您要求的不完全相同,但在处理这些高阶函数时可能有助于提供另一种选择。您可以在Apple的文档中详细了解lazy。在此编辑中,文档包含以下内容:

  

var lazy:LazyCollection>这个系列的视图   它提供了通常渴望操作的惰性实现,例如   作为地图和过滤器。

     

var lazy:LazySequence>含有它的序列   元素作为这个序列,但在其中的一些操作,如map   和过滤,懒洋洋地实施。

答案 2 :(得分:0)

如果你拥有该数组中的所有对象,它们应该符合一些协议,它实现了变量isFulfilled ...正如你所看到的,你可以让这些对象变为混淆(让我们称之为满意的协议) )...现在您可以将该数组转换为[FulfilledItem]类型......现在您可以继续使用

我在这里粘贴代码以便您更好地理解:

你看,你不能扩展Any或AnyObject,因为AnyObject是协议而且不能扩展(我猜想是Apple的意思),但你可以,sublass"协议或您喜欢称之为专业 - 使协议继承自AnyObject ...

 protocol FulfilledItem: AnyObject{

    var isFulfilled: Bool {get set}

}

class itemWithTrueValue: FulfilledItem{
    var isFulfilled: Bool = true
}

class itemWithFalseValue: FulfilledItem{
    var isFulfilled: Bool = false
}

var arrayOfFulFilled: [FulfilledItem] = [itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue()]

  let boolValue =   arrayOfFulFilled.contains(where: {
       $0.isFulfilled == false
    })

现在我们已经拥有了一个非常好看的自定义协议,继承了所有Any属性+我们漂亮的isFulfilled属性,我们现在将通常处理...

根据苹果文档:

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html#//apple_ref/doc/uid/TP40014097-CH22-ID342

AnyObject仅用于引用类型(类),Any用于值和引用类型,所以我想它更喜欢继承AnyObject ...

现在您将AnyObject转换为数组协议项FulfilledItem,您将拥有漂亮的解决方案(不要忘记每个项目符合该协议并设置值......)

祝快乐编码:)