Split a large array into two arrays

I have a large array of objects and would like to split it into two arrays containing objects in an alternative order.

Example:

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

Becomes these two arrays (they should alternate)

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

There are many ways to split an array. But, what is the most efficient (least expensive) if the array is huge.

+6
source share
5 answers

There are various fancy ways to do this with a filter, but most of them will probably require two passes, not one, so you can just use a for-loop.

Reserving space forward can be of great importance in this case, because if the source is large, it will avoid unnecessary redistribution as new arrays grow, and calculating the required space at constant time on arrays.

 // 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]) 

If performance is really important, you can use source.withUnsafeBufferPointer to access the source elements to avoid checking the bounds of the index.

If the arrays are really huge, and you are not going to use the data, except as an example of a small number of elements, you can use the lazy representation instead (although the std lib lazy filter is not very useful here, since it returns a sequence, not a collection - maybe you you will need to write your own).

+4
source

You can use a loop for a step to populate the two resulting arrays as follows:

 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] 

update: 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) } } 
+4
source

A more concise, functional approach would be to use 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] 
+4
source

Use for loops. If the index value is equal, then send it to one array, and if the index value is odd, send it to the odd array.

0
source

Here, in my opinion, the easiest way

 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() 
0
source

Source: https://habr.com/ru/post/983810/


All Articles