在两个元素的数组中拆分大数组

Posted

技术标签:

【中文标题】在两个元素的数组中拆分大数组【英文标题】:Split large Array in Array of two elements 【发布时间】:2015-09-20 00:53:37 【问题描述】:

我有大量对象,我需要将它们分成一组两个元素以供 UI 提案使用。

例子:

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

用这四个数组变成一个数组

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

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

【问题讨论】:

我没有测试效率,但这包含一个可能的解决方案:***.com/questions/26691123/…。 看到这个***.com/questions/5731042/… @heapach:我认为 Swift 编译器不接受 Java 源代码 :) 哦,对不起..查看标签可能会有所帮助:-D 请参阅my answer for a similar question,其中显示了多达 5 种不同的方法来解决您的问题。 【参考方案1】:

如果您正在寻找效率,您可以使用一种方法来懒惰地生成每个包含 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 中使用它?【参考方案2】:

您可以使用oisdk 的出色SwiftSequence 框架。 chunk 函数可以满足您的需求:

[1, 2, 3, 4, 5].chunk(2)

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

还有更多的序列功能,你一定要看看。

你可以看看他对chunkhere的实现(它使用了生成器)

【讨论】:

【参考方案3】:

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

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

【讨论】:

【参考方案4】:

或者,您可以为此使用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

【讨论】:

【参考方案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 
    

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

注意,这适用于任何可切片的东西,比如字符串:

"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]

【讨论】:

【参考方案6】:

斯威夫特 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]]

【讨论】:

【参考方案7】:

到目前为止,我看到的最短解决方案(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)])
        
    


【讨论】:

以上是关于在两个元素的数组中拆分大数组的主要内容,如果未能解决你的问题,请参考以下文章

如何将一个大数组按照里面相同的数据拆分成多个子数组

如何将一个大数组按照里面相同的数据拆分成多个子数组

如何获取两个数组相同元素

java 怎样将数组里的元素进行拆分

如何在javascript中将大数组拆分为小数组? [复制]

labview 数组中相邻元素抽取和组合(截取)