【问题标题】:how to merge several arrays into one array with alternating values in Swift?如何在 Swift 中将多个数组合并为一个具有交替值的数组?
【发布时间】:2017-04-28 13:35:53
【问题描述】:

如何将多个数组合并为一个值交替的数组?

例如:

var arr1 = [1, 2, 3, 4, 5]
var arr2 = [a, b, c, d, e, f, g]
var arr3 = [aa, bb, cc, dd]

[1, a, aa, 2, b, bb, 3, c, cc, 4, d, dd, 5, e, f, g]

【问题讨论】:

  • 这不是我想要的。查看结果数组。
  • 第一个:是acaabb 变量吗?因为您似乎将它们视为字符串文字。第二:你试过什么? stackoverflow.com/help/how-to-ask
  • @AntonVolkov,您的编辑使用了单引号,这可能在 Ruby 或 Python 中有效,但 Swift 对字符和字符串使用双引号。

标签: swift


【解决方案1】:

如果 3 个数组中的元素类型相同,则可以计算最大大小并使用 flatMap 将它们合并。

例如:

var arr1 = ["1", "2", "3", "4", "5"]
var arr2 = ["a", "b", "c", "d", "e", "f", "g"]
var arr3 = ["aa", "bb", "cc", "dd","ee"]

let arrays    = [arr1,arr2,arr3]
let merged    = (0..<arrays.map{$0.count}.max()!)
               .flatMap{i in arrays.filter{i<$0.count}.map{$0[i]} }

[编辑] 或者,如果您想为给定类型的任意数量的数组提供更通用的解决方案,您可以创建一个函数来执行此操作:

func mergeArrays<T>(_ arrays:[T] ...) -> [T]
{ 
  return (0..<arrays.map{$0.count}.max()!)
         .flatMap{i in arrays.filter{i<$0.count}.map{$0[i]} }
}  

let merged = mergeArrays(arr1,arr2,arr3)            

[EDIT2] 删除了 zip 的使用,这稍微简化了表达式。

在此处保留 zip 方法以供将来参考:

func mergeArrays<T>(_ arrays:[T] ...) -> [T]
{ 
   return arrays.reduce([[T]]())
   { zip($0,$1).map{$0+[$1]} + $0.dropFirst($1.count) + $1.dropFirst($0.count).map{[$0]} }
   .flatMap{$0}
}    

它可能会更快一些。我没量过

【讨论】:

    【解决方案2】:

    我为你做了一个函数。您可以使用几个不同的数组作为参数

    var arr1 = [1, 2, 3, 4, 5]
    var arr2 = ["a", "b", "c", "d", "e", "f", "g"]
    var arr3 = ["aa", "bb", "cc", "dd"]
    
    func combine<T>(arrays:[[T]]) -> [T] {
    
        let maxCount = arrays.reduce(0) { max($0, $1.count) }
    
        var result = [T]()
    
        for i in 0..<maxCount {
            for array in arrays {
                if i < array.count {
                    result.append(array[i])
                }
            }
        }
    
        return result
    
    }
    
    combine(arrays: [arr1,arr2,arr3] as [[Any]])
    // or
    combine(arrays: [arr2,arr3]) // if type is the same
    

    【讨论】:

    • 与其使用Any,不如引入一个类型参数T作为func combine&lt;T&gt; (arrays:[[T]]) -&gt; [T] { ... }
    • 不,我不应该 :) 因为没有通用的固定类型“T”,数组可能是不同的类型...
    • 使用T,如果所有数组都具有相同的类型,它将返回正确的类型。如果它们不同,请使用let combined = combine(arrays: [arr1, arr2, arr3] as [[Any]]) 调用它。
    • 好的,@vacawama 你赢了。不过,这似乎是有意义的。
    • 只要你给 Swift 一些东西,它就能搞定T。例如,这也适用:let result: [Any] = combine(arrays: [arr1,arr2,arr3])。你会想使用一个数组都实现的协议,或者一个通用的超类可以工作。
    【解决方案3】:

    试试这个:

    extension Array {
    
        //Mutating
        mutating func weave(with array: Array) -> Array {
            precondition(!isEmpty && !array.isEmpty)
            var weavedArray = Array<Element>()
            weavedArray.reserveCapacity(count + array.count)
            var inputArray = array
            for _ in 0..<[count, array.count].min()! {
                weavedArray.append(self.removeFirst())
                weavedArray.append(inputArray.removeFirst())
            }
            let largerArr = largerOf(self, inputArray)
            if largerArr.count != 0 {
                weavedArray.append(contentsOf: largerArr)
            }
            self = weavedArray
            return weavedArray
        }
    
        //Non-mutating
        func weaved(with array: Array) -> Array {
            precondition(!isEmpty && !array.isEmpty)
            var weavedArray = Array<Element>()
            weavedArray.reserveCapacity(count + array.count)
            var selfArray = self
            var inputArray = array
            for _ in 0..<[count, array.count].min()! {
                weavedArray.append(selfArray.removeFirst())
                weavedArray.append(inputArray.removeFirst())
            }
            let largerArr = largerOf(selfArray, inputArray)
            if largerArr.count != 0 {
                weavedArray.append(contentsOf: largerArr)
            }
            return weavedArray
        }
    
        internal func largerOf<T>(_ arr1: Array<T>, _ arr2: Array<T>) -> Array<T> {
            switch (arr1.count, arr2.count) {
            case (let a, let b) where a > b: return arr1
            case (let a, let b) where a < b: return arr2
            case (let a, let b) where a == b: return arr1
            default: return arr2
            }
        }
    }
    

    用法

    变异 - .weave(with: )

    let odds = [1, 3, 5, 7, 9]
    let evens = [2, 4, 6, 8, 10]
    
    odds.weave(with: evens)
    
    print(odds) //prints: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    print(evens) //prints: [2, 4, 6, 8, 10]
    

    非变异 - .weaved(with: )

    let odds = [1, 3, 5, 7, 9]
    let evens = [2, 4, 6, 8, 10]
    
    let firstTen = odds.weaved(with: evens)
    
    print(firstTen) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    print(odds) //prints: [1, 3, 5, 7, 9]
    priny(evens) //prints: [2, 4, 6, 8, 10]
    

    希望对您有所帮助,如果您还有其他问题,请随时提问!

    【讨论】:

      【解决方案4】:

      我认为没有通用功能,但实现它相当简单:

          var sumArr: [Any] = []
          let max_count = max(arr1.count, arr2.count, arr3.count)
          for i in 0...max_count {
              if arr1.count > i { sumArr.append(arr1[i]) }
              if arr2.count > i { sumArr.append(arr2[i]) }
              if arr3.count > i { sumArr.append(arr3[i]) }
           }
      

      或者让我们让它更可重用:

          func combineArrays(arrays: [[Any]]) -> [Any] {
              var sumArr: [Any] = []
              guard let max_count = arrays.map({$0.count}).max() else { return [] }
              for i in 0...max_count {
                  for arr in arrays {
                      if arr.count > i { sumArr.append(arr[i]) }
                  }
              }
              return sumArr
          }
      

      【讨论】:

      • 你的函数应该使用类型参数T,而不是Any,因为元素无关紧要并且没有理由通过返回Any来丢失类型信息。 func combineArrays&lt;T&gt; (arrays: [[T]]) -&gt; [T] { ... }
      • 无需使用map 获取最大计数arrays.max(by: {$0.count &gt; $1.count})?.count
      • 在我们吹毛求疵的时候;在结果上跳过mapmax - 这是reduce 的问题:arrays.reduce(0) { max($0, $1.count) }
      • @LeoDabus 你的方法到底比map 的方法好多少?
      【解决方案5】:

      你可以试试这个

      var c = 0
      var i = 0
      var arr1 = [1, 2, 3, 4, 5]
      var arr2 = [a, b, c, d, e, f, g]
      var arr3 = [aa, bb, cc, dd]
      var arr = [] 
      while (c < 3) {
          if i < arr1.count {
              arr.append(arr1[i])
          } else {
              c += 1
          }
          if i < arr2.count {
              arr.append(arr2[i])
          } else {
              c += 1
          }
          if i < arr3.count {
              arr.append(arr3[i])
          } else {
              c += 1
          }
          i += 1
      }
      

      【讨论】:

      • 仅供参考 - c = c+1 可以写成 c += 1
      • @EgorT 不,不是。您正在考虑 ++-- 运算符。
      • @rmaddy 哎呀!我的错误:)
      【解决方案6】:

      这是我给你的解决方案:

      const arr1 = [1, 2, 3, 4, 5]
      const arr2 = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
      const arr3 = ['aa', 'bb', 'cc', 'dd']
      
      const displayAlternatedValues = (a, b, c) => {
        const allArraysInOne = [a, b, c]
        let arrayOfLengths = []
        let arrayOfAlternatedValues = []
      
        for (let i = 0; i < allArraysInOne.length; i++) {
          const findMaxLength = arrayOfLengths.push(allArraysInOne[i].length)
        } 
      
        const maxLength = Math.max(... arrayOfLengths)
        // this function allows us to find the length of iteration for the next 'for'
      
        for (let i = 0; i < maxLength; i++) {
          const associateAlternedValues = [a[i], b[i], c[i]]
          const pushAlternedValues = arrayOfAlternatedValues.push(...associateAlternedValues)
        }
        // this function allows us to create a new array with values sorted by their index
      
        const cleanedAlternedValues = arrayOfAlternatedValues.filter(elem => typeof elem !=='undefined')
      
        // this variable create a clean array, without displaying 'undefined' in case there 
        // is no value matching a[i], b[i], c[i]
      
        return cleanedAlternedValues
      
      }
      
      displayAlternatedValues(arr1, arr2, arr3)
      
      // result : [ 1, 'a', 'aa', 2, 'b', 'bb', 3, 'c', 'cc', 4, 'd', 'dd', 5, 'e', 'f', 'g' ]
      

      希望这会有所帮助!我还在学习 !

      【讨论】:

        猜你喜欢
        • 2019-02-27
        • 2018-04-14
        • 2019-03-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-09
        相关资源
        最近更新 更多