Как я могу чередовать два массива?

Если у меня есть два массива, например

let one = [1,3,5]
let two = [2,4,6]

Я хотел бы объединить/перемежать массивы в следующем шаблоне [один [0], два [0], один [1], два [1] и т.д.].

//prints [1,2,3,4,5,6]
let comibned = mergeFunction(one, two)
print(combined)

Что было бы хорошим способом реализации функции объединения?

func mergeFunction(one: [T], _ two: [T]) -> [T] {
    var mergedArray = [T]()
    //What goes here
    return mergedArray
}

Ответ 1

Если оба массива имеют одинаковую длину, то это возможное решение:

let one = [1,3,5]
let two = [2,4,6]

let merged = zip(one, two).flatMap { [$0, $1] }

print(merged) // [1, 2, 3, 4, 5, 6]

Здесь zip() перечисляет массивы параллельно и возвращает последовательность пар (2-элементные кортежи) с одним элементом из каждого массива. flatMap() создает 2-элементный массив из каждой пары и конкатенирует результат.

Если массивы могут иметь разную длину, вы добавляете дополнительные элементы более длинного массива к результату:

func mergeFunction<T>(one: [T], _ two: [T]) -> [T] {
    let commonLength = min(one.count, two.count)
    return zip(one, two).flatMap { [$0, $1] } 
           + one.suffixFrom(commonLength)
           + two.suffixFrom(commonLength)
}

Обновление для Swift 3:

func mergeFunction<T>(_ one: [T], _ two: [T]) -> [T] {
    let commonLength = min(one.count, two.count)
    return zip(one, two).flatMap { [$0, $1] } 
           + one.suffix(from: commonLength)
           + two.suffix(from: commonLength)
}

Ответ 2

Если вы просто хотите чередовать два массива, вы можете просто сделать что-то вроде:

let maxIndex = max(one.count, two.count)
var mergedArray = Array<T>()
for index in 0..<maxIndex {
    if index < one.count { mergedArray.append(one[index]) }
    if index < two.count { mergedArray.append(two[index]) }
}

return mergedArray

Ответ 3

С Swift 5 вы можете использовать один из следующих примеров кодов Playground, чтобы решить вашу проблему.


# 1. Использование функции zip(_:_:) и flatMap(_:) Collection flatMap(_:)

let one = [1, 3, 5]
let two = [2, 4, 6]

let array = zip(one, two).flatMap({ [$0, $1] })
print(array) // print: [1, 2, 3, 4, 5, 6]

Apple заявляет:

Если две последовательности, переданные в zip(_:_:) имеют разную длину, результирующая последовательность имеет ту же длину, что и более короткая последовательность.


# 2. Использование функции sequence(state:next:)

let one = [1, 3, 5]
let two = [2, 4, 6]

let unfoldSequence = sequence(state: (false, one.makeIterator(), two.makeIterator()), next: { state -> Int? in
    state.0.toggle()
    return state.0 ? state.1.next() : state.2.next()
})
let array = Array(unfoldSequence)
print(array) // print: [1, 2, 3, 4, 5, 6]

# 3. Использование AnyIterator init(_:) инициализатор

let one = [1, 3, 5]
let two = [2, 4, 6]

var oneIterator = one.makeIterator()
var twoIterator = two.makeIterator()
var state = false

let anyIterator = AnyIterator<Int> {
    state.toggle()
    return state ? oneIterator.next() : twoIterator.next()
}

let array = Array(anyIterator)
print(array) // print: [1, 2, 3, 4, 5, 6]

В качестве альтернативы вы можете обернуть свои итераторы в экземпляр AnySequence:

let one = [1, 3, 5]
let two = [2, 4, 6]

let anySequence = AnySequence<Int>({ () -> AnyIterator<Int> in
    var oneIterator = one.makeIterator()
    var twoIterator = two.makeIterator()
    var state = false

    return AnyIterator<Int> {
        state.toggle()
        return state ? oneIterator.next() : twoIterator.next()
    }
})

let array = Array(anySequence)
print(array) // print: [1, 2, 3, 4, 5, 6]