将多个数组合并成一个,并按顺序进行索引

3
我有多个数组(最多15个),每个数组最多可以有1800个对象。
我需要将它们合并成一个单一的数组,以便我可以应用分隔符(',')生成csv文件。问题是当我将它们合并成一个单一的数组时,必须按顺序合并,就像首先插入每个数组的第一个对象,然后是第二个索引的对象,然后是第三个对象,以此类推。
我能够通过使用for-in循环实现所需的结果。但是这不是非常高效。我认为可以使用Swift中可用的更加简洁的函数方法(使用map、reduce和filter函数)来完成这个任务。
然而,我无法完美地将它们结合起来。有人可以帮助我使用Swift函数方法来实现这个结果吗?
附言:如果您想让我发布for-in循环代码,请告诉我,但我认为这不是必需的。

是的,我看到了。我也正在尝试不同的解决方案,因为这似乎是一个好问题。如果我在周末找到更好的答案,我会更新我的答案;否则,我将接受下面给出的答案之一。干杯!! :) - Rameswar Prasad
4个回答

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
太好了。我尝试了不同的值和不同大小的数组。一切都按预期工作。非常感谢。我将您的最后一行更新为Swift 3.0语法。 - Rameswar Prasad
1
它完美地工作,但是我仍然有一个疑问,在仔细查看后,排序函数的条件是如何工作的?{ $0.0 < $0.1 },您正在比较同一元组的偏移量和元素之间的差异,而不是在下一个元素的偏移量之间进行比较。无法理解那个。 :) - Rameswar Prasad
等等,但那不是正确的答案。我已经测试过了。顺序从1、10、100、1000变成了1、10、1000、100。 - Rameswar Prasad
我使用了4个数组,但是它没有提供正确的结果,之前的条件是完美的,所以我感到困惑。 - Rameswar Prasad
@Rameswar:你能给我那4个数组吗?这些数组导致了错误的结果。 - Luca Angeletti
显示剩余3条评论

2

我认为可以将其作为数组的扩展来实现(尽管请注意,您无法直接这样做,请参见此问答)。您可以使用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))。对于大型数组,这种额外的成本可能是不可忽略的。

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

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)

我尝试对此进行实验,但在排序函数后它给出了错误的输出。我将相同的值更改为包含不同的值。例如:第一个数组包含1、2、3...;第二个数组包含10、20、30...;第三个数组包含100、200、300...以此类推。在排序函数之后,它变成了1、10、1000、100,而应该是1、10、100、1000。这里顺序出现了错误。 - Rameswar Prasad
嘿,你能加入我们在这里的聊天吗 --> http://chat.stackoverflow.com/rooms/124193/discussion-between-rameswar-and-appzyourlife - Rameswar Prasad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接