You are right that a good way to approach shuffling a 2-D array is to flatten it and shuffle the values. The tricky part is how to get the shuffled values back into the original structure of the array.
By making the shuffled array into an iterator iter, we can call iter.next() to get each value and use nested maps to access and replace the original values:
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]]
Make it into a Generic Function: func shuffle2D<T>(_ arr: [[T]]) -> [[T]]
We can turn this into a generic function which can shuffle any 2D array:
func shuffle2D<T>(_ arr: [[T]]) -> [[T]] {
var iter = arr.joined().shuffled().makeIterator()
return arr.map { $0.compactMap { _ in iter.next() }}
}
Note: I have changed the internal map into a compactMap so that we can avoid force unwrapping iter.next().
Examples:
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]]