在两个元素的数组中拆分大数组
Split large Array in Array of two elements
我有很多对象,我需要将它们分成一组两个元素以供 UI 提案。
示例:
[0, 1, 2, 3, 4, 5, 6]
这四个数组组成一个数组
[[0, 1], [2, 3], [4, 5], [6]]
拆分数组的方法有很多种。但是,如果数组很大,什么是最有效(成本最低)的。
如果您正在寻求效率,您可以使用一种方法来延迟生成每个包含 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 = [[=10=]]
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
您可以使用 oisdk's awesome SwiftSequence 框架。 chunk
函数可以完全满足您的需求:
[1, 2, 3, 4, 5].chunk(2)
[[1, 2], [3, 4], [5]]
还有很多更多的序列函数,你一定要看看。
你可以看看他的实现 chunk
here(它使用生成器)
也许不是最有效的解决方案,但却是最直接的解决方案:
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
或者,您可以为此使用 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
}
如果你想要一个子切片数组,你可以使用 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)
returns ["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]
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]]
目前为止我看到的最短解法(Swift 4)来自 Gist:
extension Array {
func chunks(chunkSize: Int) -> [[Element]] {
return stride(from: 0, to: self.count, by: chunkSize).map {
Array(self[[=10=]..<Swift.min([=10=] + chunkSize, self.count)])
}
}
}
我有很多对象,我需要将它们分成一组两个元素以供 UI 提案。
示例:
[0, 1, 2, 3, 4, 5, 6]
这四个数组组成一个数组
[[0, 1], [2, 3], [4, 5], [6]]
拆分数组的方法有很多种。但是,如果数组很大,什么是最有效(成本最低)的。
如果您正在寻求效率,您可以使用一种方法来延迟生成每个包含 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 = [[=10=]]
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
您可以使用 oisdk's awesome SwiftSequence 框架。 chunk
函数可以完全满足您的需求:
[1, 2, 3, 4, 5].chunk(2)
[[1, 2], [3, 4], [5]]
还有很多更多的序列函数,你一定要看看。
你可以看看他的实现 chunk
here(它使用生成器)
也许不是最有效的解决方案,但却是最直接的解决方案:
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
或者,您可以为此使用 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
}
如果你想要一个子切片数组,你可以使用 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)
returns ["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]
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]]
目前为止我看到的最短解法(Swift 4)来自 Gist:
extension Array {
func chunks(chunkSize: Int) -> [[Element]] {
return stride(from: 0, to: self.count, by: chunkSize).map {
Array(self[[=10=]..<Swift.min([=10=] + chunkSize, self.count)])
}
}
}