这里是另一种可能的“功能性”方法。作为一个工具,我们需要一种根据谓词“截断”序列的方法。以下代码使用了来自
https://github.com/oisdk/SwiftSequence/blob/master/SwiftSequence/TakeDrop.swift的思路。
首先,定义一个生成器类型的
takeWhile
:
extension GeneratorType {
func takeWhile(predicate : (Element) -> Bool) -> AnyGenerator<Element> {
var gen = self
return anyGenerator( { gen.next().flatMap( { predicate($0) ? $0 : nil }) })
}
}
现在将"lift"方法应用到序列类型:
extension SequenceType {
func takeWhile(predicate : (Generator.Element) -> Bool) -> AnySequence<Generator.Element> {
return AnySequence( { self.generate().takeWhile(predicate) })
}
}
这可以被广泛使用,这里有一个简单的例子:
for i in [1, 4, 2, 5, 3].takeWhile( {$0 < 5} ) {
print(i)
}
“公共前缀(common prefix)”函数现在可以定义为:
extension String {
func commonPrefixWith(other: String) -> String {
return String(zip(self.characters, other.characters).takeWhile({$0 == $1}).map({ $1 }))
}
}
例子:
let firstString = "abc1xy"
let secondString = "abc2x"
let common = firstString.commonPrefixWith(secondString)
print(common) // abc
解释:
zip(self.characters, other.characters)
同时枚举两个字符序列,并创建一个(惰性评估的)
对序列。
("a", "a"), ("b", "b"), ("c", "c"), ("1", "2"), ("x", "x")
.takeWhile({$0 == $1})
限制了该序列仅包含两个字符串中相同字符的初始部分:
("a", "a"), ("b", "b"), ("c", "c")
.map({ $1 })
将每个元组映射到第二个元素,并返回数组
[ "a", "b", "c"]
最后,String(...)
将字符组合成字符串。
从 Swift 4 开始,序列有一个 prefix(while:)
方法,它接受一个布尔谓词,在这里可以使用它来代替定义自定义的 takeWhile
方法:
extension String {
func commonPrefix(with other: String) -> String {
return String(zip(self, other).prefix(while: { $0.0 == $0.1 }).map { $0.0 })
}
}
字符串是由它们的字符组成的集合。
(使用2017年5月17日的Swift 4.0快照进行测试。)