将大数组拆分为两个数组

时间:2015-03-15 02:43:08

标签: arrays swift

我有一大堆对象,并希望将它分成两个包含交替顺序对象的数组。

示例:

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

成为这两个阵列(他们应该交替使用)

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

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

7 个答案:

答案 0 :(得分:4)

您可以使用 for stride 循环来填充两个结果数组,如下所示:

extension Array {
    var groupOfTwo:(firstArray:[T],secondArray:[T]) {
        var firstArray:[T] = []
        var secondArray:[T] = []
        for index in stride(from: 0, to: count, by: 2) {
            firstArray.append(self[index])
            if index + 1 < count {
                secondArray.append(self[index+1])
            }
        }
        return (firstArray,secondArray)
    }
}



[0, 1, 2, 3, 4, 5, 6].groupOfTwo.firstArray   // [0, 2, 4, 6]
[0, 1, 2, 3, 4, 5, 6].groupOfTwo.secondArray  // [1, 3, 5]

更新: Xcode 7.1.1•Swift 2.1

extension Array {
    var groupOfTwo:(firstArray:[Element],secondArray:[Element]) {
        var firstArray:[Element] = []
        var secondArray:[Element] = []
        for index in 0.stride(to: count, by: 2) {
            firstArray.append(self[index])
            if index + 1 < count {
                secondArray.append(self[index+1])
            }
        }
        return (firstArray,secondArray)
    }
}

答案 1 :(得分:4)

使用过滤器可以使用各种奇特的方法,但大多数可能需要两次传递而不是一次,所以你也可以只使用for循环。

在这种情况下预留空间可能会产生很大的不同,因为如果源很大,它将避免在新阵列增长时不必要的重新分配,并且所需空间的计算在数组上是恒定的时间。 / p>

// could make this take a more generic random-access collection source
// if needed, or just make it an array extension instead
func splitAlternating<T>(source: [T]) -> ([T],[T]) {
    var evens: [T] = [], odds: [T] = []

    evens.reserveCapacity(source.count / 2 + 1)
    odds.reserveCapacity(source.count / 2)

    for idx in indices(source) {
        if idx % 2 == 0 {
            evens.append(source[idx])
        }
        else {
            odds.append(source[idx])
        }
    }

    return (evens,odds)
}

let a = [0,1,2,3,4,5,6]
splitAlternating(a)  // ([0, 2, 4, 6], [1, 3, 5])

如果性能真的很重要,可以使用source.withUnsafeBufferPointer访问源元素,以避免索引边界检查。

如果数组非常大,你不会使用结果数据,除了采样少量元素之外,你可以考虑使用惰性视图(尽管std lib)懒惰过滤器在这里使用不多,因为它返回序列而不是集合 - 你可能需要编写自己的。)

答案 2 :(得分:4)

更简洁,功能性的方法是使用reduce

let a = [0,1,2,3,4,5,6]

let (evens, odds) = a.enumerate().reduce(([Int](),[Int]())) { (cur, next) in
    let even = next.index % 2 == 0
    return (cur.0 + (even ? [next.element] : []),
            cur.1 + (even ? [] : [next.element]))
}

evens // [0,2,4,6]
odds // [1,3,5]

答案 3 :(得分:0)

用于循环。如果索引值是偶数,那么将其发送到一个数组,如果索引值是奇数,则将其发送到奇数数组。

答案 4 :(得分:0)

在我看来,这是最简单的方法

old_list = [0, 1, 2, 3, 4, 5, 6]
new_list1 =[]
new_list2 = []
while len(old_list)>0:
    new_list1.append(old_list.pop(-1))
    if len(old_list) != 0:
        new_list2.append(old_list.pop(-1))

new_list1.reverse()
new_list2.reverse()

答案 5 :(得分:0)

我只需要在一个位置将一个数组拆分为两个,再将另一个拆分为三个数组即可。所以我建立了这个:

Protected Sub Button1_Click(sender As Object, e As EventArgs)
        Dim dataSet = JsonConvert.DeserializeObject(Of DataSet)(TextBox1.Text)
        Dim table = dataSet.Tables(0)

    End Sub

它适用于Swift 4.2和5.0(从Xcode 10.2 beta 2开始为5.0)

答案 6 :(得分:0)

大/大数组在进行部分处理时总是会出现问题,例如在这种情况下,因为创建两个额外的(即使是半大小的)数组可能会浪费时间和内存。例如,如果您只想计算奇数和偶数位置数字的均值和标准差,但是这将需要调用一个专用函数,该函数需要一个序列作为输入?

因此为什么不创建两个子集合,而不是复制数组内容,而是以透明的方式指向原始数组,以允许查询元素:

extension Collection where Index: Strideable{
    func stride(from: Index, to: Index, by: Index.Stride) -> StridedToCollection<Self> {
        return StridedToCollection(self, from: from, to: to, by: by)
    }
}

struct StridedToCollection<C>: Collection where C: Collection, C.Index: Strideable {
    private let _subscript : (C.Index) -> C.Element
    private let step: C.Index.Stride

    fileprivate init(_ collection: C, from: C.Index, to: C.Index, by: C.Index.Stride)  {
        startIndex = from
        endIndex = Swift.max(to, startIndex)
        step = by
        _subscript = { collection[$0] }
    }

    let startIndex: C.Index
    let endIndex: C.Index

    func index(after i: C.Index) -> C.Index {
        let next = i.advanced(by: step)
        return next >= endIndex ? endIndex : next
    }

    subscript(_ index: C.Index) -> C.Element {
        return _subscript(index)
    }
}

Collection扩展名和关联的结构将创建一个伪数组,您可以使用该伪数组仅访问您感兴趣的元素。

用法很简单:

let numbers: [Int] = [1, 2, 3, 4]
let stride1 = numbers.stride(from: 0, to: numbers.count, by: 2)
let stride2 = numbers.stride(from: 1, to: numbers.count, by: 2)
print(Array(stride1), Array(stride2))

使用上述方法,您可以迭代两个步骤,而不必担心会使内存量增加一倍。而且,如果您实际上需要两个子数组,则只需Array(stride)-对其进行修饰。