我有一大堆对象,并希望将它分成两个包含交替顺序对象的数组。
示例:
[0, 1, 2, 3, 4, 5, 6]
成为这两个阵列(他们应该交替使用)
[0, 2, 4, 6]
和[1, 3, 5]
分割阵列有很多种方法。但是,如果阵列很大,那么最有效(成本最低)的是什么。
答案 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)
-对其进行修饰。