将大数组拆分为两个元素的数组

10

我有一个大型对象列表,我需要将它们分成两个元素的组,以便用于UI目的。

例如:

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

变成了这四个数组

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

有很多方法可以拆分一个数组。但是,如果数组很大,则最有效(成本最小)的方法是什么。


2
我没有测试过效率,但这里包含了一个可能的解决方案:https://dev59.com/AITba4cB1Zd3GeqP_M2g#26691258。 - Martin R
请查看此链接:https://dev59.com/L2025IYBdhLWcg3w6KSO - heaphach
3
我认为Swift编译器不接受Java源代码 :) - Martin R
哦,抱歉..看一下标签可能会有帮助 :-D - heaphach
请看我在类似问题上的回答,其中展示了解决你问题的多达5种不同方法 - Imanou Petit
7个回答

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 }
    }
}

Subslices非常高效,因为它们通常与原始可切片实体共享内部存储。因此,不会为存储元素分配新的内存 - 只有跟踪子片段指向原始数组的指针的内存。

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

"Hello, I must be going"
    .characters
    .splitEvery(3)
    .map(String.init)

返回结果为 ["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]

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

这种方法适用于任何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)
}

针对Swift 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

我如何在Swift 1.2中使用它而不使用协议扩展? - Douglas Ferreira

3

Swift 2 Gist

let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

extension Array {
    func splitBy(subSize: Int) -> [[Element]] {
        return 0.stride(to: self.count, by: subSize).map { startIndex in
            let endIndex = startIndex.advancedBy(subSize, limit: self.count)
            return Array(self[startIndex ..< endIndex])
        }
    }
}

let chunks = arr.splitBy(5)

print(chunks) // [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12]]

2

到目前为止,我看过的最简短的解决方案(Swift 4)来自Gist

extension Array {

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

}

0
你可以使用oisdk的强大SwiftSequence框架。其中有一个chunk函数,它恰好可以满足你的需求:
[1, 2, 3, 4, 5].chunk(2)

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

此外,序列还有很多其他函数,您绝对应该查看一下。

您可以在这里查看他实现的chunk链接(它使用生成器)


0

也许不是最高效的解决方案,但却是最直接的解决方案:

func toPairs(numbers:[Int])->[[Int]]
{
    var pairs:[[Int]]=[]
    var pair:[Int]=[]
    for var index=0;index<numbers.count;index++ {
        pair.append(numbers[index])
        if pair.count == 2 || index==numbers.count-1 {
            pairs.append(pair)
            pair=[]
        }
    }
    return pairs
}

var numbers=[0,1,2,3,4,5]

var pairs=toPairs(numbers)

print(pairs)

我的笔记本电脑上的输出:

[[0, 1], [2, 3], [4, 5]]
Program ended with exit code: 0

0

或者,您可以使用reduce来实现这一点,但这可能不是最有效的方法:

let res = a.reduce([[Int]]()) { (var acc: [[Int]], current: Int) in

    if acc.last != nil && acc.last?.count < 2 {
        var newLast = acc.last
        newLast?.append(current)
        acc.removeLast()

        acc.append(newLast!)
    } else {
        acc.append([current])
    }
    return acc
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接