鉴于我在Swift中有一个数组,例如[1,2,3,4],有一种方法pairs()会将其转换为元组数组:[(1,2), (2,3), (3,4)]。
[1,2,3,4]
pairs()
[(1,2), (2,3), (3,4)]
以下是一些有关pairs()行为方式的示例:
pairs([])
[]
pairs([1])
pairs([1,2])
[(1,2)]
我可以为此编写代码Array,但我想pairs()作为的扩展使用Sequence,以便它返回Sequence成对的a。这将使得它可用在任何序列,并与方法,如兼容map,reduce,filter,等。
Array
Sequence
map
reduce
filter
我该如何创建这样的一个Sequence?以及如何编写Sequence以这种方式进行转换的方法,以便可以尽可能灵活地使用它?
我们可以使用zip()和dropFirst()如果我们定义的扩展Collection类型:
zip()
dropFirst()
Collection
extension Collection { func pairs() -> AnySequence<(Element, Element)> { return AnySequence(zip(self, self.dropFirst())) } }
例:
let array = [1, 2, 3, 4] for p in array.pairs() { print(p) }
输出:
(1、2) (2、3) (3,4)
更多示例:
print(Array("abc".pairs())) // [("a", "b"), ("b", "c")] print([1, 2, 3, 4, 5].pairs().map(+)) // [3, 5, 7, 9] print([3, 1, 4, 1, 5, 9, 2].pairs().filter(<)) // [(1, 4), (1, 5), (5, 9)]
(与我在此答案的第一个版本中写的不同…)将这种方法应用于时并不安全Sequence,因为不能保证可以 无损 地遍历序列多次 。
这是使用自定义迭代器类型的直接实现,该类型也适用于序列:
struct PairSequence<S: Sequence>: IteratorProtocol, Sequence { var it: S.Iterator var last: S.Element? init(seq: S) { it = seq.makeIterator() last = it.next() } mutating func next() -> (S.Element, S.Element)? { guard let a = last, let b = it.next() else { return nil } last = b return (a, b) } } extension Sequence { func pairs() -> PairSequence<Self> { return PairSequence(seq: self) } }
print(Array([1, 2, 3, 4].pairs().pairs())) // [((1, 2), (2, 3)), ((2, 3), (3, 4))]