Swift 是否有像 Any 或 All 这样的短路高阶函数?
Does Swift have short-circuiting higher-order functions like Any or All?
我知道 Swift 的高阶函数,如 Map、Filter、Reduce 和 FlatMap,但我不知道 'All' 或 'Any' return 一个布尔值,在枚举结果时对正测试进行短路。
例如,假设您有一个包含 10,000 个对象的集合,每个对象都有一个名为 isFulfilled
的 属性,您想要查看该集合中是否有任何对象将 isFulfilled
设置为 false .在 C# 中,您可以使用 myObjects.Any(obj -> !obj.isFulfilled)
,当满足该条件时,它将使枚举的其余部分短路并立即 return true
.
Swift里面有这样的东西吗?
Sequence
(特别是 Collection
和 Array
)有一个(短路)contains(where:)
方法以布尔谓词作为参数。例如,
if array.contains(where: { [=10=] % 2 == 0 })
检查数组是否包含任何偶数。
没有"all"方法,但你也可以使用contains()
通过否定谓词和结果。例如,
if !array.contains(where: { [=11=] % 2 != 0 })
检查数组中的所有个数是否为偶数。当然你可以定义一个自定义的扩展方法:
extension Sequence {
func allSatisfy(_ predicate: (Iterator.Element) -> Bool) -> Bool {
return !contains(where: { !predicate([=12=]) } )
}
}
如果你想允许 "throwing" 谓词与
contains
方法那么它将被定义为
extension Sequence {
func allSatisfy(_ predicate: (Iterator.Element) throws -> Bool) rethrows -> Bool {
return try !contains(where: { try !predicate([=13=]) } )
}
}
更新: 正如 James Shapiro 正确注意到的那样,allSatisfy
方法已添加到 [=52 中的 Sequence
类型=] 4.2(目前处于测试阶段),参见
(需要最近的 4.2 开发者快照。)
您可以在 Swift 中做的另一件事类似于 "short circuiting" 在这种情况下是使用集合的 lazy
属性,这将将您的实现更改为如下内容:
myObjects.lazy.filter({ ![=10=].isFulfilled }).first != nil
这与您要求的并不完全相同,但在处理这些高阶函数时可能有助于提供另一种选择。您可以在 Apple 文档中阅读有关 lazy
的更多信息。截至此次编辑,文档包含以下内容:
var lazy: LazyCollection> A view onto this collection
that provides lazy implementations of normally eager operations, such
as map and filter.
var lazy: LazySequence> A sequence containing the same
elements as this sequence, but on which some operations, such as map
and filter, are implemented lazily.
如果您拥有该数组中的所有对象,它们应该符合某种协议,该协议实现了变量 isFulfilled... 如您所见,您可以使这些对象符合(让我们称之为 fulFilled 协议)。 .. 现在您可以将该数组转换为类型 [FulfilledItem]... 现在您可以照常继续
我在这里粘贴代码以便您更好地理解:
你看,你不能扩展 Any 或 AnyObject,因为 AnyObject 是协议,不能扩展(我猜是 Apple 的意图),但你可以,,子类化协议或者你喜欢专业地称呼它 - Make继承自 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: {
[=10=].isFulfilled == false
})
现在我们已经有了一个非常漂亮的自定义协议,它继承了所有 Any 属性 + 我们漂亮的 isFulfilled 属性,我们现在将像往常一样处理它...
根据苹果文档:
AnyObject 仅适用于引用类型(类),Any 既适用于值类型也适用于引用类型,所以我猜它更倾向于继承AnyObject...
现在您将 AnyObject 转换为 Array 协议 Item FulfilledItem 并且您将获得漂亮的解决方案(不要忘记每个项目都符合该协议并设置值...)
祝编码愉快:)
我知道 Swift 的高阶函数,如 Map、Filter、Reduce 和 FlatMap,但我不知道 'All' 或 'Any' return 一个布尔值,在枚举结果时对正测试进行短路。
例如,假设您有一个包含 10,000 个对象的集合,每个对象都有一个名为 isFulfilled
的 属性,您想要查看该集合中是否有任何对象将 isFulfilled
设置为 false .在 C# 中,您可以使用 myObjects.Any(obj -> !obj.isFulfilled)
,当满足该条件时,它将使枚举的其余部分短路并立即 return true
.
Swift里面有这样的东西吗?
Sequence
(特别是 Collection
和 Array
)有一个(短路)contains(where:)
方法以布尔谓词作为参数。例如,
if array.contains(where: { [=10=] % 2 == 0 })
检查数组是否包含任何偶数。
没有"all"方法,但你也可以使用contains()
通过否定谓词和结果。例如,
if !array.contains(where: { [=11=] % 2 != 0 })
检查数组中的所有个数是否为偶数。当然你可以定义一个自定义的扩展方法:
extension Sequence {
func allSatisfy(_ predicate: (Iterator.Element) -> Bool) -> Bool {
return !contains(where: { !predicate([=12=]) } )
}
}
如果你想允许 "throwing" 谓词与
contains
方法那么它将被定义为
extension Sequence {
func allSatisfy(_ predicate: (Iterator.Element) throws -> Bool) rethrows -> Bool {
return try !contains(where: { try !predicate([=13=]) } )
}
}
更新: 正如 James Shapiro 正确注意到的那样,allSatisfy
方法已添加到 [=52 中的 Sequence
类型=] 4.2(目前处于测试阶段),参见
(需要最近的 4.2 开发者快照。)
您可以在 Swift 中做的另一件事类似于 "short circuiting" 在这种情况下是使用集合的 lazy
属性,这将将您的实现更改为如下内容:
myObjects.lazy.filter({ ![=10=].isFulfilled }).first != nil
这与您要求的并不完全相同,但在处理这些高阶函数时可能有助于提供另一种选择。您可以在 Apple 文档中阅读有关 lazy
的更多信息。截至此次编辑,文档包含以下内容:
var lazy: LazyCollection> A view onto this collection that provides lazy implementations of normally eager operations, such as map and filter.
var lazy: LazySequence> A sequence containing the same elements as this sequence, but on which some operations, such as map and filter, are implemented lazily.
如果您拥有该数组中的所有对象,它们应该符合某种协议,该协议实现了变量 isFulfilled... 如您所见,您可以使这些对象符合(让我们称之为 fulFilled 协议)。 .. 现在您可以将该数组转换为类型 [FulfilledItem]... 现在您可以照常继续
我在这里粘贴代码以便您更好地理解:
你看,你不能扩展 Any 或 AnyObject,因为 AnyObject 是协议,不能扩展(我猜是 Apple 的意图),但你可以,,子类化协议或者你喜欢专业地称呼它 - Make继承自 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: {
[=10=].isFulfilled == false
})
现在我们已经有了一个非常漂亮的自定义协议,它继承了所有 Any 属性 + 我们漂亮的 isFulfilled 属性,我们现在将像往常一样处理它...
根据苹果文档:
AnyObject 仅适用于引用类型(类),Any 既适用于值类型也适用于引用类型,所以我猜它更倾向于继承AnyObject...
现在您将 AnyObject 转换为 Array 协议 Item FulfilledItem 并且您将获得漂亮的解决方案(不要忘记每个项目都符合该协议并设置值...)
祝编码愉快:)