在Swift中一次迭代收集两个

时间:2015-12-31 19:01:26

标签: swift

说我有一个数组[1, 2, 3, 4, 5]。我怎样才能一次迭代两个?

Iteration 1: (1, 2)
Iteration 2: (3, 4)
Iteration 3: (5, nil)

8 个答案:

答案 0 :(得分:18)

您可以使用名为stride(to:,by :)的渐进循环来迭代每n个元素的元素:

Xcode 8.3.2•Swift 3.1

let array = Array(1...5)

let pairs = stride(from: 0, to: array.endIndex, by: 2).map {
    (array[$0], $0 < array.index(before: array.endIndex) ? array[$0.advanced(by: 1)] : nil)
}   // [(.0 1, {some 2}), (.0 3, {some 4}), (.0 5, nil)]

print(pairs)  // "[(1, Optional(2)), (3, Optional(4)), (5, nil)]\n"

答案 1 :(得分:3)

如果数组具有偶数个元素,您可以编写如下内容:

for i in 0..<arr.count/2 {
    print(arr[2*i...2*i+1])
}

然而情况并非如此。此外,nil并不总是与数组中的元素类型兼容,例如示例中的元素类型(nilInt不兼容,仅与Int?)兼容。

另一个解决方案是扩展Array并添加一个pair()方法,该方法返回一个元组(元组可以是异构的)。您可以使用pair遍历数组中的所有对,或者,您可以扩展Array结构,并添加返回元组数组的pairs()。请注意,由于元组中的第二个元素是Optional,因此您需要在使用前将其解包。

extension Array {
    func pair(at i: Index) -> (Element, Element?) {
        return (self[i], i < self.count - 1 ? self[i+1] : nil)
    }

    func pairs() -> [(Element, Element?)] {
        guard !isEmpty else { return [] }
        var result = [(Element, Element?)]()
        for i in 0...arr.count/2 {
            result.append(self.pair(at: 2*i))
        }
        return result
    }
}

let arr = [1, 2, 3, 4, 5]

for i in 0...arr.count/2 {
    print(arr.pair(at: 2*i))
}

for pair in arr.pairs() {
    print(pair)
}

更新使用map代替手动循环,可以简化上述两种解决方案:

let pairs = (0..<arr.count/2).map { (arr[$0*2], arr[$0*2+1]) }
print(pairs) // prints [(1, 2), (3, 4)]

或,对于Array扩展程序:

extension Array {
    func pair(at i: Index) -> (Element, Element?) {
        return (self[i], i < self.count - 1 ? self[i+1] : nil)
    }

    func pairs() -> [(Element, Element?)] {
        guard !isEmpty else { return [] }
        return (0..<(arr.count/2 + arr.count%2)).map { pair(at: $0*2) }
    }
}

let arr = [1, 2, 3, 4, 5]
print(arr.pairs()) // [(1, Optional(2)), (3, Optional(4)), (5, nil)]

您可以扩展Collection,以便为所有馆藏提供此pair功能:

extension Collection {
    func pairs() -> [(Element, Element?)] {
        guard !isEmpty else { return [] }
        return (0..<count/2+count%2).map {
            let i1 = index(startIndex, offsetBy: $0*2)
            let i2 = index(startIndex, offsetBy: $0*2+1)
            return (self[i1], i2 < endIndex ? self[i2] : nil)
        }
    }
}

答案 2 :(得分:3)

您可以使用sequence()和迭代器的next()方法进行迭代 对成对的连续元素。这适用于任意序列, 不仅是数组:

let a = "ABCDE"

for pair in sequence(state: a.makeIterator(), next: { it in
    it.next().map { ($0, it.next()) }
}) {
    print(pair)
}

输出:

("A", Optional("B"))
("C", Optional("D"))
("E", nil)

“外部” it.next()产生偶数位置的元素,或nil (在这种情况下,it.next().map { }的计算结果也为nil,并且 序列终止)。 “内部” it.next()产生元素 在奇数位置或nil上。

作为任意序列的扩展方法:

extension Sequence {
    func pairs() -> AnyIterator<(Element, Element?)> {
        return AnyIterator(sequence(state: makeIterator(), next: { it in
            it.next().map { ($0, it.next()) }
        }))
    }
}

示例:

let seq = (1...).prefix(5)
for pair in seq.pairs() { print(pair) }

请注意,这些对是 lazyly 生成的,没有中间数组 被建造。 如果您想要一个包含所有对的数组,那么

let pairs = Array([1, 2, 3, 4, 5].pairs())
print(pairs) // [(1, Optional(2)), (3, Optional(4)), (5, nil)]

完成工作。

答案 3 :(得分:2)

我个人不喜欢在列表的一半中循环(主要是因为划分),所以我喜欢这样做:

let array = [1,2,3,4,5];
var i = 0;

while i < array.count {
    var a = array[i];
    var b : Int? = nil;
    if i + 1 < array.count {
        b = array[i+1];
    }
    print("(\(a), \(b))");

    i += 2;
}

通过递增2来循环遍历数组。

如果您想在元素中使用nil,则需要使用选项。

答案 4 :(得分:2)

这与询问的内容不同,但是我在Sequence上使用了扩展名,该扩展名生成了将数组按任意所需大小分块的数组数组:

extension Sequence {
    func clump(by clumpsize:Int) -> [[Element]] {
        let slices : [[Element]] = self.reduce(into:[]) {
            memo, cur in
            if memo.count == 0 {
                return memo.append([cur])
            }
            if memo.last!.count < clumpsize {
                memo.append(memo.removeLast() + [cur])
            } else {
                memo.append([cur])
            }
        }
        return slices
    }
}

所以[1, 2, 3, 4, 5].clump(by:2)产生[[1, 2], [3, 4], [5]],现在您可以根据需要进行迭代。

答案 5 :(得分:0)

一种方法是将数组封装在一个类中。获取项目对的返回值将是选项,以防止超出范围的呼叫。

示例:

class Pairs {

    let source = [1, 2, 3, 4, 5]  // Or set with init()
    var offset = 0

    func nextpair() -> (Int?, Int?) {
        var first: Int? = nil
        var second: Int? = nil
        if offset < source.count {
            first = source[offset]
            offset++
        }
        if offset < source.count {
            second = source[offset]
            offset++
        }
        return (first, second)
    }

}

答案 6 :(得分:0)

扩展以拆分数组。

extension Array {
   func chunked(into size: Int) -> [[Element]] {
      return stride(from: 0, to: count, by: size).map {
      Array(self[$0 ..< Swift.min($0 + size, count)]) }
   }
}

let result = [1...10].chunked(into: 2)

答案 7 :(得分:0)

这是我的解决方案,包含一个 reduce 和几个 guard

extension Array {
  var touplesOfTwo: [(Element,Element?)] {
    self.reduce(into: [(Element,Element?)]()) {
      guard let last = $0.last else { $0.append( ($1,nil) ); return }
      let lastIndex = $0.count - 1
      guard let _ = last.1 else { $0[lastIndex].1 = $1; return }
      $0.append( ($1,nil) )
    }
  }
}
let list = [1,4,3,7,2,9,6,5]
let queues = list.map { $0 }
let touplesList = queues.touplesOfTwo
print("\(touplesList)")
// [(1, Optional(4)), (3, Optional(7)), (2, Optional(9)), (6, Optional(5))]