I have this code that generates a shuffle map to display children in a random order:
import React from "react"
function shuffle(array) {
let currentIndex = array.length
let randomIndex
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
}
return array;
}
let lastShuffle
function generateShuffleMap(l) {
if (l === 0) return [];
if (l === 1) return [0];
let arr = new Array(l)
for (let i = 0; i < arr.length; ++i) {
arr[i] = i
}
let r = Math.random()
console.log("ShuffleChildren randomNumber", r)
arr.randomNumber = r
while (true) {
shuffle(arr)
if (lastShuffle === undefined) {
console.log("ShuffleChildren lastShuffle undefined", arr, lastShuffle)
return arr
}
for (let i = 0; i < arr.length; ++i) {
console.log("ShuffleChildren compare", arr[i], lastShuffle[i])
if (arr[i] !== lastShuffle[i]) {
console.log("ShuffleChildren found mismatch!", arr, arr.randomNumber, lastShuffle, lastShuffle.randomNumber)
return arr
}
}
// Identical shuffle. Try again.
console.log("ShuffleChildren try again")
}
}
export default function ShuffleChildren(props) {
const [map, setMap] = React.useState(()=>{
let m = generateShuffleMap(props.children.length)
lastShuffle = m
console.log("ShuffleChildren memo", m, m.randomNumber)
//shuffleMapTest(2, 60)
return m
})
console.log("ShuffleChildren render", map, map.randomNumber)
return React.Children.toArray(props.children).map((v, k) => props.children[map[k]])
}
Sounds pretty simple. It makes sure you don't get the same shuffle twice by trying again. So a series of length-2 shuffles would be [0, 1], [1, 0], [0, 1], etc. But here's my output:
ShuffleChildren randomNumber 0.5832622841674447
ShuffleChildren lastShuffle undefined Array [ 1, 0 ] undefined
ShuffleChildren memo Array [ 1, 0 ] 0.5832622841674447
ShuffleChildren render Array [ 1, 0 ] 0.5832622841674447
ShuffleChildren randomNumber 0.396479700829085
ShuffleChildren compare 0 0
ShuffleChildren compare 1 1
ShuffleChildren try again
ShuffleChildren compare 1 0
ShuffleChildren found mismatch! Array [ 1, 0 ] 0.396479700829085 Array [ 0, 1 ] 0.7683400651535296
ShuffleChildren memo Array [ 1, 0 ] 0.396479700829085
ShuffleChildren render Array [ 1, 0 ] 0.396479700829085
ShuffleChildren randomNumber 0.4286083485990334
ShuffleChildren compare 1 0
ShuffleChildren found mismatch! Array [ 1, 0 ] 0.4286083485990334 Array [ 0, 1 ] 0.6164973053401377
ShuffleChildren memo Array [ 1, 0 ] 0.4286083485990334
ShuffleChildren render Array [ 1, 0 ] 0.4286083485990334
I'm getting [1, 0] three times in a row. And what's more, on found mismatch!
lastShuffle is an array with a random number I didn't even generate! I wrote some tests to investigate:
function shuffleTest(l, n) {
let permutations = {}
for (let i = 0; i < n; ++i) {
let arr = new Array(l)
for (let i = 0; i < arr.length; ++i) {
arr[i] = i
}
arr = shuffle(arr)
let join = arr.join(',')
permutations[join] = permutations[join] || 0
permutations[join]++
}
console.log(`ShuffleChildren shuffleTest(${l}, ${n})`, permutations)
}
function shuffleMapTest(l, n) {
let permutations = {}
for (let i = 0; i < n; ++i) {
let arr = generateShuffleMap(l)
lastShuffle = arr
let join = arr.join(',')
permutations[join] = permutations[join] || 0
permutations[join]++
}
console.log(`ShuffleChildren shuffleMapTest(${l}, ${n})`, permutations)
}
But the individual functions themselves seem to be functioning.
ShuffleChildren shuffleTest(2, 100) Object { "0,1": 53, "1,0": 47 }
ShuffleChildren shuffleTest(2, 1000) Object { "1,0": 492, "0,1": 508 }
ShuffleChildren shuffleMapTest(2, 100) Object { "1,0": 50, "0,1": 50 }
ShuffleChildren shuffleMapTest(2, 1000) Object { "1,0": 500, "0,1": 500 }
What is even going on here? How could randomNumber
have changed without me knowing about it?
Aucun commentaire:
Enregistrer un commentaire