拆分包含两个元素的Array中的大型数组

Dou*_*ira 7 arrays slice swift

我有大量的对象列表,我需要将它们分成一组两个元素用于UI propouse.

例:

[0, 1, 2, 3, 4, 5, 6]

成为这四个数组的数组

[[0, 1], [2, 3], [4, 5], [6]]

分割阵列有很多种方法.但是,如果阵列很大,那么最有效(成本最低)的是什么.

Air*_*ity 5

如果您想要一个子切片数组,您可以使用该split函数使用一个闭包生成它,该闭包捕获一个状态变量并在它经过每个元素时递增它,仅在每第 n 个元素上拆分。作为Sliceable(仅限 Swift 2.0,需要是 1.2 中的免费函数)的扩展:

extension Sliceable {
    func splitEvery(n: Index.Distance) -> [SubSlice] {
        var i: Index.Distance = 0
        return split(self) { _ in ++i % n == 0 }
    }
}
Run Code Online (Sandbox Code Playgroud)

子切片非常高效,因为它们通常与原始切片实体共享内部存储。所以不会分配新的内存来存储元素——只有内存用于跟踪子切片的指向原始数组的指针。

请注意,这适用于任何可切片的内容,例如字符串:

"Hello, I must be going"
    .characters
    .splitEvery(3)
    .map(String.init)
Run Code Online (Sandbox Code Playgroud)

返回["He", "lo", " I", "mu", "t ", "e ", "oi", "g"]

如果你想懒洋洋地拆分数组(即生成一个仅按需提供子切片的序列),你可以使用anyGenerator以下代码编写它:

extension Sliceable {
    func lazilySplitEvery(n: Index.Distance) -> AnySequence<SubSlice> {

        return AnySequence { () -> AnyGenerator<SubSlice> in
            var i: Index = self.startIndex
            return anyGenerator {
                guard i != self.endIndex else { return nil }
                let j = advance(i, n, self.endIndex)
                let r = i..<j
                i = j
                return self[r]
            }
        }
    }
}


for x in [1,2,3,4,5,6,7].lazilySplitEvery(3) {
    print(x)
}
// prints [1, 2, 3]
//        [4, 5, 6]
//        [7]
Run Code Online (Sandbox Code Playgroud)


ois*_*sdk 4

如果您正在寻求效率,您可以使用一种方法来延迟生成每个包含 2 个元素的数组,因此您一次只在内存中存储 2 个元素:

public struct ChunkGen<G : GeneratorType> : GeneratorType {

  private var g: G
  private let n: Int
  private var c: [G.Element]

  public mutating func next() -> [G.Element]? {
    var i = n
    return g.next().map {
      c = [$0]
      while --i > 0, let next = g.next() { c.append(next) }
      return c
    }
  }

  private init(g: G, n: Int) {
    self.g = g
    self.n = n
    self.c = []
    self.c.reserveCapacity(n)
  }
}

public struct ChunkSeq<S : SequenceType> : SequenceType {

  private let seq: S
  private let n: Int

  public func generate() -> ChunkGen<S.Generator> {
    return ChunkGen(g: seq.generate(), n: n)
  }
}

public extension SequenceType {
  func chunk(n: Int) -> ChunkSeq<Self> {
    return ChunkSeq(seq: self, n: n)
  }
}

var g = [1, 2, 3, 4, 5].chunk(2).generate()

g.next() // [1, 2]
g.next() // [3, 4]
g.next() // [5]
g.next() // nil
Run Code Online (Sandbox Code Playgroud)

此方法适用于任何数组SequenceType,而不仅仅是数组。

对于 Swift 1,如果没有协议扩展,您将获得:

public struct ChunkGen<T> : GeneratorType {

  private var (st, en): (Int, Int)
  private let n: Int
  private let c: [T]

  public mutating func next() -> ArraySlice<T>? {
    (st, en) = (en, en + n)
    return st < c.endIndex ? c[st..<min(en, c.endIndex)] : nil
  }

  private init(c: [T], n: Int) {
    self.c = c
    self.n = n
    self.st = 0 - n
    self.en = 0
  }
}

public struct ChunkSeq<T> : SequenceType {

  private let c: [T]
  private let n: Int

  public func generate() -> ChunkGen<T> {
    return ChunkGen(c: c, n: n)
  }
}

func chunk<T>(ar: [T], #n: Int) -> ChunkSeq<T> {
  return ChunkSeq(c: ar, n: n)
}
Run Code Online (Sandbox Code Playgroud)

对于斯威夫特 3:

public struct ChunkIterator<I: IteratorProtocol> : IteratorProtocol {

  fileprivate var i: I
  fileprivate let n: Int

  public mutating func next() -> [I.Element]? {
    guard let head = i.next() else { return nil }
    var build = [head]
    build.reserveCapacity(n)
    for _ in (1..<n) {
      guard let x = i.next() else { break }
      build.append(x)
    }
    return build
  }

}

public struct ChunkSeq<S: Sequence> : Sequence {

  fileprivate let seq: S
  fileprivate let n: Int

  public func makeIterator() -> ChunkIterator<S.Iterator> {
    return ChunkIterator(i: seq.makeIterator(), n: n)
  }
}

public extension Sequence {
  func chunk(_ n: Int) -> ChunkSeq<Self> {
    return ChunkSeq(seq: self, n: n)
  }
}

var g = [1, 2, 3, 4, 5].chunk(2).makeIterator()

g.next() // [1, 2]
g.next() // [3, 4]
g.next() // [5]
g.next() // nil
Run Code Online (Sandbox Code Playgroud)