I currently acheive shuffle one of array without duplicated with previous value of next value.
However, I don't think my method is good. I think there are better way.
Firstly, I will describe what the array looks like.
it's an array of object with property {answer,url,category} and there are duplicated item in the array. think as [A,A,B,B,C,C] , A,B,C as object here.
As EzioMerce pointed out, in this array, object will always has equal amount of numbers. such if there are 3 A, will definitely have 3 B and C. It will not have array as such [A,A,A,B]
I need the array to shuffle until there is no consecutive object next to each other such as [A,B,C,B,A,C]
Here is my solution (which I have tested 40 times without consecutive object):
getShuffleWords(array: Card[]) {
//First shuffle..
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor( Math.random() * (i - 1));
if (j > 0) {
//make sure there are no simliar value around position i and j
if (array[i]?.answer !== array[j - 1]?.answer
&& array[i]?.answer !== array[j 1]?.answer
&& array[i]?.answer !== array[j - 1]?.answer
&& array[i]?.answer !== array[j 1]?.answer) {
[array[i], array[j]] = [array[j], array[i]];
}
} else {
if (array[i]?.answer !== array[j 1]?.answer) {
[array[i], array[j]] = [array[j], array[i]];
}
}
}
const before = [...array];
console.log(before);
//Checking duplicate and swap with other value
for (let x = 0; x < array.length; x ){
if (array[x].answer == array[x 1]?.answer) {
console.log(x,array[x])
for (let y = 0; y < array.length; y ){
//make sure there are no simliar value around position x and y
if (array[y]?.answer !== array[x]?.answer
&& array[y 1]?.answer !== array[x].answer
&& array[y - 1]?.answer !== array[x].answer
&& array[y]?.answer !== array[x 1]?.answer
&& array[y]?.answer !== array[x-1]?.answer
) {
console.log(y, array[y]);
if (x < y) {
[array[x], array[y]] = [array[y], array[x]];
} else {
[array[y], array[x]] = [array[x], array[y]];
}
break;
}
}
}
}
//just another caculate if there is duplication left (for testing purpose)
let dup = 0;
for (let x = 0; x < array.length; x ){
if (array[x].answer == array[x 1]?.answer) {
dup ;
}
}
console.log(array, dup);
return array;
}
However, in the //First shuffle.. there are always has some consecutive object exisited in the array. thats why I repeat another checking and replace the value.
How would I improve my method. and why my first shuffle does not work perfectly?
CodePudding user response:
You could shuffle until you got a result which has no neighbour indices.
const
fy = array => { // fisher-yates, adapted from https://stackoverflow.com/a/59837259/1447675
let i = array.length;
while (--i) {
const j = Math.floor(Math.random() * (i 1));
[array[j], array[i]] = [array[i], array[j]];
}
},
shuffle = array => {
do fy(array);
while (array.some((v, i, a) => Math.abs(v - a[i 1]) === 1))
};
indices = [...Array(10).keys()];
shuffle(indices);
console.log(...indices);
CodePudding user response:
You can try this way. It also works if arr
will be an array of objects
const arr = [1, 2, 3, 1, 2, 3, 1, 2, 3];
const shuffle = (arr) => {
const uniqueArr = [...(new Set(arr))];
const shuffledArr = [];
let countOfOneObj = 0;
for (const obj of arr) {
if (obj === arr[0]) countOfOneObj;
};
const getRandomObj = () => {
const i = Math.floor(Math.random() * uniqueArr.length);
return uniqueArr[i];
}
for (let i = 0; i < countOfOneObj; i) {
let usedObjs = []
for (let j = 0; j < uniqueArr.length; j) {
const obj = getRandomObj();
if (
usedObjs.includes(obj) ||
shuffledArr[shuffledArr.length - 1] === obj
) {
--j;
continue;
}
usedObjs.push(obj);
shuffledArr.push(obj);
}
usedObjs = [];
}
return shuffledArr;
}
console.log(shuffle(arr));