How can I interleave two arrays?

前端 未结 4 1186
予麋鹿
予麋鹿 2020-11-29 12:20

If I have two arrays e.g

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

I would like to merge/interleave the arrays in the following pattern [one[0],

相关标签:
4条回答
  • 2020-11-29 12:31

    If both arrays have the same length then this is a possible solution:

    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]
    

    Here zip() enumerates the arrays in parallel and returns a sequence of pairs (2-element tuples) with one element from each array. flatMap() creates a 2-element array from each pair and concatenates the result.

    If the arrays can have different length then you append the extra elements of the longer array to the result:

    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)
    }
    

    Update for 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)
    }
    
    0 讨论(0)
  • 2020-11-29 12:50
      /// Alternates between the elements of two sequences.
      /// - Parameter keepSuffix:
      /// When `true`, and the sequences have different lengths,
      /// the suffix of `interleaved`  will be the suffix of the longer sequence.
      func interleaved<Sequence: Swift.Sequence>(
        with sequence: Sequence,
        keepingLongerSuffix keepSuffix: Bool = false
      ) -> AnySequence<Element>
      where Sequence.Element == Element {
        keepSuffix
        ? .init { () -> AnyIterator<Element> in
          var iterators = (
            AnyIterator( self.makeIterator() ),
            AnyIterator( sequence.makeIterator() )
          )
          return .init {
            defer { iterators = (iterators.1, iterators.0) }
            return iterators.0.next() ?? iterators.1.next()
          }
        }
        : .init(
          zip(self, sequence).lazy.flatMap { [$0, $1] }
        )
      }
    
    let oddsTo7 = stride(from: 1, to: 7, by: 2)
    let evensThrough10 = stride(from: 2, through: 10, by: 2)
    let oneThrough6 = Array(1...6)
    
    XCTAssertEqual(
      Array( oddsTo7.interleaved(with: evensThrough10) ),
      oneThrough6
    )
    
    XCTAssertEqual(
      Array(
        oddsTo7.interleaved(with: evensThrough10, keepingLongerSuffix: true)
      ),
      oneThrough6 + [8, 10]
    )
    
    0 讨论(0)
  • 2020-11-29 12:53

    If you're just looking to interleave two arrays, you could just do something like:

    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
    
    0 讨论(0)
  • 2020-11-29 12:56

    With Swift 5, you can use one of the following Playground sample codes in order to solve your problem.


    #1. Using zip(_:_:) function and Collection's flatMap(_:) method

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

    Apple states:

    If the two sequences passed to zip(_:_:) are different lengths, the resulting sequence is the same length as the shorter sequence.


    #2. Using an object that conforms to Sequence and IteratorProtocol protocols

    struct InterleavedSequence<T>: Sequence, IteratorProtocol {
    
        private let firstArray: [T]
        private let secondArray: [T]
        private let thresholdIndex: Int
        private var index = 0
        private var toggle = false
    
        init(firstArray: [T], secondArray: [T]) {
            self.firstArray = firstArray
            self.secondArray = secondArray
            self.thresholdIndex = Swift.min(firstArray.endIndex, secondArray.endIndex)
        }
    
        mutating func next() -> T? {
            guard index < thresholdIndex else { return nil }
            defer {
                if toggle {
                    index += 1
                }
                toggle.toggle()
            }
            return !toggle ? firstArray[index] : secondArray[index]
        }
    
    }
    
    let one = [1, 3, 5, 7]
    let two = [2, 4, 6]
    
    let sequence = InterleavedSequence(firstArray: one, secondArray: two)
    let array = Array(sequence)
    print(array) // print: [1, 2, 3, 4, 5, 6]
    
    0 讨论(0)
提交回复
热议问题