如何改组多维数组?

时间:2019-06-25 07:54:59

标签: swift multidimensional-array shuffle

我正在尝试随机地整理2D数组。我该怎么做? 我只知道用改组方法改组一个数组的方法。我应该将所有2d数组合并为一个大数组,然后将其改组为2d数组,还是有更好的方法?

<IfModule mod_php7.c>
   php_value max_execution_time 500
</IfModule>

4 个答案:

答案 0 :(得分:2)

您是对的,对2D数组进行改组的一种好方法是将其展平并改组值。棘手的部分是如何将经过改组的值恢复为数组的原始结构。

通过将经过改组的数组放入迭代器iter中,我们可以调用iter.next()获取每个值,并使用嵌套的map来访问和替换原始值:

var arr = [[1], [2, 3], [4, 5, 6]]

var iter = arr.joined().shuffled().makeIterator()

let arr2 = arr.map { $0.map { _ in iter.next()! } }

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

使其成为通用函数:func shuffle2D<T>(_ arr: [[T]]) -> [[T]]

我们可以将其转换为通用函数,该函数可以随机播放任何2D数组:

func shuffle2D<T>(_ arr: [[T]]) -> [[T]] {
    var iter = arr.joined().shuffled().makeIterator()

    return arr.map { $0.compactMap { _ in iter.next() }}
}

注意:我将内部map更改为compactMap,以便避免强行拆开iter.next()

示例:

print(shuffle2D([[1, 2, 3], [4, 5, 6]]))
[[2, 5, 6], [3, 1, 4]]
print(shuffle2D([["a", "b"], ["c", "d"], ["e", "f"]]))
[["e", "a"], ["b", "d"], ["f", "c"]]
let array = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
             [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
             [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
             [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
             [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
             [2, 2, 2, 2, 2, 0, 0, 0, 0, 0],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

let shuffled = shuffle2D(array)
print(shuffled)
[[0, 1, 0, 1, 1, 0, 1, 1, 0, 0], [0, 1, 0, 0, 1, 1, 1, 2, 0, 1], [0, 1, 1, 1, 0, 1, 1, 1, 1, 1], [1, 0, 1, 0, 2, 1, 2, 1, 0, 1], [1, 0, 0, 0, 2, 1, 1, 0, 1, 1], [1, 1, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 1, 1, 2, 0, 0, 1, 1, 0], [1, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 1, 1, 0, 1, 1, 1, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0]]

答案 1 :(得分:1)

您可以使用for循环遍历外部数组,并通过shuffle方法对迭代的每个数组进行混洗。这是我用伪代码编写的想法:

for inner_array in outer_array:
    shuffle(inner_array)

编辑

据我所知,您将尝试以不太随机的顺序将现有数组添加到新数组中,如下所示:

new_array = []
for i=0; i < oldarray.length(); i++:
    new_array.append(oldarray[randomNumber])

您将必须寻找可能的重复项(即通过从旧数组中删除for循环中的数组),并导致您的randomNumber在旧数组的边界之间生成。

实际上,您可以根据需要将第一个答案和第二个答案一起使用。

答案 2 :(得分:1)

首先从多维数组中获得一个组合的混洗数组,即

let arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
let shuffled = arr.joined().shuffled() //[1, 2, 5, 6, 11, 9, 4, 7, 12, 3, 8, 10]

创建一个扩展程序,将单个数组划分为多个块,即

extension Array {
    func chunks(of size: Int) -> [[Element]] {
        return stride(from: 0, to: self.count, by: size).map {
            Array(self[$0 ..< Swift.min($0 + size, count)])
        }
    }
}

用法:

let result = shuffled.chunks(of: 3) [[3, 1, 2], [5, 6, 4], [7, 8, 9], [11, 10, 12]]

答案 3 :(得分:0)

您总是可以这样:

var matrix = [[1, 3, 2], [7, 1, 2], [9, 4, 1]]
var shuffled = matrix.map({ $0.shuffled() })

print(shuffled)

可能的输出之一是

[[3, 2, 1], [2, 7, 1], [9, 4, 1]]

编辑:

但是,如果要对整个矩阵进行混洗,则可能应该先对矩阵进行FlatMap处理,对数组进行混洗,然后将数组分块为矩阵。

如果您担心性能,则应执行一些众所周知的数组改组算法(Knuth shuffle),但矩阵应完整无缺。相反,请使用线性矩阵变体(将矩阵位置(x,y)转换为矢量位置(y *(x-1))+ y)