【问题标题】:How to shuffle multidimensional array?如何洗牌多维数组?
【发布时间】:2019-06-25 07:54:59
【问题描述】:

我正在尝试随机打乱二维数组。我该怎么做? 我只知道用洗牌方法洗牌一个数组的方法。我应该将所有二维数组组合成一个大数组并改组并使其成为二维数组还是有更好的方法?

[[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]]

【问题讨论】:

  • 你能添加一个预期的输出吗?我希望我的问题是正确的,但我可能是错的。

标签: swift multidimensional-array shuffle


【解决方案1】:

您说得对,对二维数组进行洗牌的一个好方法是展平它并对值进行洗牌。棘手的部分是如何将洗牌后的值恢复到数组的原始结构中。

通过将打乱的数组变成一个迭代器iter,我们可以调用iter.next()来获取每个值,并使用嵌套的maps来访问和替换原始值:

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]]

我们可以把它变成一个通用函数,可以打乱任何二维数组:

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]]

【讨论】:

    【解决方案2】:

    首先从多维数组中得到一个单独的组合shuffled数组,即

    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]]
    

    【讨论】:

    • arr.flatMap({ $0.shuffled() }) 将分别打乱每一行,然后连接结果。它不会混合来自不同行的值。
    • @MartinR 是的。那个也是。感谢更新。我认为这更相关。
    【解决方案3】:

    您可以使用 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 是在旧数组的边界之间生成的。

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

    【讨论】:

    • 问题是,正如 Martin R 所说,这只会打乱矩阵的每一行。
    • 好吧,看来我答错了。你想改组外部数组吗?还是内部和外部数组?
    【解决方案4】:

    你总是可以这样做:

    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]]
    

    编辑:

    如果要对整个矩阵进行打乱,您可能应该首先对矩阵进行平面映射,打乱数组,然后将数组重新分块成矩阵。

    如果您担心性能,那么您应该执行一些众所周知的数组混洗算法 (Knuth shuffle),但要保持矩阵不变。相反,使用线性化矩阵变体(将矩阵位置 (x, y) 转换为向量位置 (y * (x - 1)) + y)

    【讨论】:

    • 但这不会混合来自不同行的值。
    猜你喜欢
    • 1970-01-01
    • 2019-02-07
    • 2019-08-18
    • 2020-07-20
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 2011-05-05
    相关资源
    最近更新 更多