将多个数组合并为一个,按顺序索引

时间:2016-09-26 06:50:50

标签: arrays swift functional-programming

我有多个数组(最多15个),每个最多可以有1800个对象。

我需要将它们组合成一个数组,以便我可以应用分隔符(',')来生成csv文件。问题是当我将它们组合成一个单独的数组时,它必须按顺序组合,就像每个数组的第一个对象应该先插入,然后是第二个对象索引,然后是第3个,依此类推。

我能够通过使用for-in循环来实现我想要的结果。然而,这并不是非常敏捷。我觉得可以使用swift中提供的功能方法(使用map,reduce和filter函数)以更清晰的方式完成。

然而,我无法将它们完美地结合起来。任何人都可以帮助我使用快速的功能方法来实现结果。

P.S:如果您希望我发布for-in循环代码,请告诉我,但我认为不需要。

4 个答案:

答案 0 :(得分:5)

给出4个(或更多)数组

let list0: [Int] = [ 1, 2, 3, 6, 7, 8, 9 ]
let list1: [Int] = [ 10, 20, 30, 40, 50, 60, 70, 80, 90]
let list2: [Int] = [ 100, 200, 300, 400, 500, 600, 700, 800, 900]
let list3: [Int] = [ 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000 ]

枚举每一个并将它们放入另一个数组

let lists = [
    list0.enumerate().map { (index: $0, array: 0, value: $1) },
    list1.enumerate().map { (index: $0, array: 1, value: $1) },
    list2.enumerate().map { (index: $0, array: 2, value: $1) },
    list3.enumerate().map { (index: $0, array: 3, value: $1) }
]

现在你可以写

let sorted = lists
    .flatten()
    .sort { ($0.index, $0.array) < ($1.index, $1.array) }
    .map { $0.value }
  

[1,10,100,1000,2,20,200,2000,3,30,300,3000,6,40,400,4000,7,50,500,5000,8,60,600, 6000,9,70,700,7000,80,800,8000,90,900,9000]

答案 1 :(得分:1)

我会考虑将其作为数组数组的扩展(但请注意,不能直接执行此操作,请参阅this Q&A)。然后,您可以使用reduce(_:_:)的组合以及flatMap(_:)的两种风格,以便通过迭代内部集合的长度并在每个给定索引处提取元素来顺序合并数组。

extension Array where Element : RandomAccessCollection, Element.Index == Int, Element.IndexDistance == Element.Index {

    func joinedByTransposing() -> [Element.Iterator.Element] {

        // The maximum length of the inner collections. Obviously if the 2D array is
        // guaranteed to be n*m, you can optimise by just taking the first inner
        // collection's count (and obviously you'll want to check that the array isn't empty first).
        let maxIndex = self.reduce(0, {$0 > $1.count ? $0 : $1.count})

        // Iterates through the max length of the inner collections, joining the restantant collections
        // from the transform below into a single array.
        return (0..<maxIndex).flatMap { index in

            // Iterate through each inner collection, getting the element at the current index of iteration,
            // or returning nil if the index is out of bounds. This flatMap will filter out any nils.
            // If the 2D array is guarenteed to be n*m, this can be replaced by self.map { $0[index] }
            self.flatMap { innerArray in

                // Simple bounds check to get the element at the given index, or nil if out of bounds
                index < innerArray.count ? innerArray[index] : nil
            }
        }
    }
}

let array0 = [1,   2,   3,   4   ]
let array1 = [10,  20,  30       ]
let array2 = [100, 200, 300, 6, 7]

let result = [array0, array1, array2].joinedByTransposing()

print(result)

// [1, 10, 100, 2, 20, 200, 3, 30, 300, 4, 6, 7]

值得注意的是,此解决方案的总时间复杂度为O(n * m) - 而使用sorted(by:)的解决方案的时间复杂度至少为O(n * m * log(n * m) ))。对于大型阵列,这个额外的成本可能非常重要。

答案 2 :(得分:0)

以下是我在帖子中描述的问题的功能方法。

首先,我使用枚举方法对数组进行压扁,该方法返回一个元组位于数组内的元组及其值。

在此之后,你有一个带有这个元组的数组,下一步,按每个元素的偏移(位置)值对这个大数组进行排序。

一旦对数组进行了排序,您就可以使用map函数提取该值。

最后一步,一旦我们有一个带有排序值的数组,你必须将它减少为带有reduce函数的字符串

// A group of arrays
var array1: [Int] = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
var array2: [Int] = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
var array3: [Int] = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
var array4: [Int] = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

// This is **your** array
let bigOne = [ array1, array2, array3, array4 ]

// And here is the functional concatenation.
let flattedOne = bigOne.flatMap({ $0.enumerated() }).sorted(by: { $0.0 < $0.1 }).map({$0.element}).reduce("") 
{
    return $0.isEmpty ? "\($1)" : "\($0), \($1)"

}


print(flattedOne)

答案 3 :(得分:0)

这是另一种方法......

public func sort(compound array: [[Int]]) -> [Int]
{
    let max_index: Int = array.map({ $0.count }).max()!

    var sorted: [Int] = [Int]()


    (0 ..< max_index).forEach({ index in
        array.forEach()
        { 
            if $0.count > index
            {
                sorted.append($0[index])
            }
        }
    })

   return sorted
}


// A group of arrays
var array1: [Int] = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 111, 112 ]
var array2: [Int] = [ 10, 20, 3, 4, 5, 6, 7, 8, 9, 10 ]
var array3: [Int] = [ 1000, 2000, 3, 4, 5, 600, 7, 8, 9, 10, 11 ]
var array4: [Int] = [ 100, 200, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ]

let bigOne: [[Int]] = [ array1, array2, array3, array4 ]

let sorted: [Int] = sort(compound: bigOne)
print(sorted)

如果你想将数组作为CSV字符串......

print(sorted.reduce("") { return $0.isEmpty ? "\($1)" : "\($0), \($1)" })