简体   繁体   中英

Separate odd and even indexes in a sequence array

A for in loop won't work because type int is does not conform to protocol Sequence.

I have 3 arrays:

1 master array, where the array is stored

1 odd array, empty at the beginning

1 even array, empty at the beginning

The meaning is that all the odd indexes of the master array will be stored at the odd array, and the same for the even array.

    while i < masterA.count {
        evenA.append(masterA[i])
        if i > 0{
        oddA.append(masterA[i - 1])
        }
        i += 2
    }

However this does not work good enough. Anyone has a better idea?

Here is another possible solution:

let evenA = stride(from: 0, to: masterA.count, by: 2).map { masterA[$0] }
let oddA = stride(from: 1, to: masterA.count, by: 2).map { masterA[$0] }

The elements are "picked" directly from the even/odd positions in the source array.

Performance comparison:

My simple, not very sophisticated ad-hoc benchmarking code:

import Swift

let N = 10_000_000
let RUNS = 50

let masterA = (0..<N).map { $0 }

var times = (0.0, 0.0, 0.0, 0.0)
for _ in 1...RUNS {

    // filter+map (dfri)
    do {
        let start = Date()
        let evenA = masterA.enumerated().filter { $0.0 % 2 == 0 }.map{ $0.1 }
        let oddA = masterA.enumerated().filter { $0.0 % 2 != 0 }.map{ $0.1 }
        let time = Date().timeIntervalSince(start)
        times.0 += time
    }

    // flatMap (dfri)
    do {
        let start = Date()
        let evenA = masterA.enumerated().flatMap { $0 % 2 == 0 ? $1 : nil }
        let oddA = masterA.enumerated().flatMap { $0 % 2 != 0 ? $1 : nil }
        let time = Date().timeIntervalSince(start)
        times.1 += time
    }

    // stride+map (me)
    do {
        let start = Date()
        let evenA = stride(from: 0, to: masterA.count, by: 2).map { masterA[$0] }
        let oddA = stride(from: 1, to: masterA.count, by: 2).map { masterA[$0] }
        let time = Date().timeIntervalSince(start)
        times.2 += time
    }

    // loop (Keiwan)
    do {
        let start = Date()
        var evenA = [Int]()
        var oddA = [Int]()

        for (index, element) in masterA.enumerated() {
            if index % 2 == 0 {
                evenA.append(element)
            } else {
                oddA.append(element)
            }
        }
        let time = Date().timeIntervalSince(start)
        times.3 += time
    }
}

print(N, RUNS)
print(times.0/Double(RUNS), times.1/Double(RUNS), times.2/Double(RUNS), times.3/Double(RUNS))

Results: (On a MacBook, running in Release mode)

#elements   filter+map  flatMap   stride+map  loop
10,000      0.0001      0.00008   0.00004     0.00004
100,000     0.0016      0.0008    0.0004      0.0004
1,000,000   0.0295      0.0136    0.0090      0.0091
10,000,000  0.3025      0.1332    0.0909      0.1250

You can use enumerated() to get both the index and the value while looping:

for (index, element) in masterA.enumerated() {
    if index % 2 == 0 {
        evenA.append(element)
    } else {
        oddA.append(element)
    }
}

This will store every element of masterA with an odd index in oddA and every element with an even index in evenA .

Possibly I'm misunderstanding your intent, but it seems as if you want that elements of masterA that have odd indices should be stored in oddA , and conversely, elements of masterA that have even indices should be stored in evenA .

You can achieve this by filtering masterA wrt the indices of masterA , readily available from masterA.enumerated() .

let masterA = [4, 5, 2, 1, 7, 8, 1]

let evenA = masterA.enumerated().filter { $0.0 % 2 == 0 }.map{ $0.1 }
let oddA = masterA.enumerated().filter { $0.0 % 2 != 0 }.map{ $0.1 }

print(evenA) // [4, 2, 7, 1]
print(oddA)  // [5, 1, 8]

As @Hamish points out in his comment below, we could use the compactMap (Swift 3: flatMap ) as an alternative to the chained filter and map .

let evenA = masterA.enumerated().compactMap { $0 % 2 == 0 ? $1 : nil }
let oddA = masterA.enumerated().compactMap { $0 % 2 != 0 ? $1 : nil }

The latter compactMap solution is briefer, whereas the filter ... map solution possibly shows intent slightly clearer. In this particular brevity vs. semantics competition, I would personally prefer the compactMap solution.

Another solution

Swift 3.0 code

let array = [1,2,3,4,5,6,7,8]
var oddArray = [Int]()
var evenArray = [Int]()

for (index,value) in array.enumerated() {
    if index % 2 == 0 {
        // It is odd because index starts from 0 in array and I am assuming the 0 index as the odd one.
        oddArray.append(value)
    } else {
        evenArray.append(value)
    }
}

Odd Array = [1,3,5,7]
Even Array = [2,4,6,8]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM