I am trying to shuffle some data from Fisher-Yates. This algorithm is easy to implement for one-dimensional arrays. However, I need to be able to shuffle data in a two-dimensional matrix.
The approach, which, I think, can generalize well to arrays with large sizes, is to convert my matrix of arbitrary size into a one-dimensional array of indices, shuffle them, and then reorganize the matrix, replacing the element with each index of this array of indices with an element in the index of an element of an index array. In other words, take a 2x2 matrix, such as:
1 2 3 4
I would convert this to this "array":
[(0, (0,0)), (1, (0,1)), (2, ((1,0)), (3, (1,1))]
Then I would scramble normal, say
[(0, (1,0)), (1, (0,1)), (2, ((1,1)), (3, (0,0))]
After the reorganization, the original matrix will become:
2 3 4 1
My basic approach is that I want to have a type class that looks something like this:
class Shufflable a where indices :: a -> Array Int b reorganize :: a -> Array Int b -> a
Then I will have a function to perform the shuffle, which looks like this:
fisherYates :: (RandomGen g) => g -> Array Int b -> (Array Int b, g)
The idea that (minus plumbing in RandomGen) I would have to shuffle a random thing like this:
shuffle :: (Shufflable a, RandomGen g) => a -> g -> (a, g) shuffle array = reorganize array (fisherYates (indices array))
Here is what I still have:
{-
My problems:
- I feel that these are many language extensions to solve a simple problem. Would it be easier to understand or write another way?
- I feel the community is moving towards type families over functional dependencies. Is there a way to use this instead to solve this problem?
- Part of me wonders if the
fisherYates
function fisherYates
move to the Shuffle
class. Would it be possible and / or worth it to do so that you either implement Shuffle
or implement both indices
and reorganize
?
Thanks!