Skip to content

Commit 669568d

Browse files
authored
Merge pull request #2811 from jspsych/fix-shuffleNoRepeats
Fixes `shuffleNoRepeats` when the equality test contains a logical OR
2 parents a45941a + 2813678 commit 669568d

File tree

3 files changed

+31
-1
lines changed

3 files changed

+31
-1
lines changed

.changeset/perfect-pugs-add.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"jspsych": patch
3+
---
4+
5+
Fixed a bug in `randomization.shuffleNoRepeats()` where having an `equalityFunction` that used a logical OR could result in some neighboring elements still evaluating to `true` via `equalityFunction`.

packages/jspsych/src/modules/randomization.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export function shuffleNoRepeats(arr: Array<any>, equalityTest: (a: any, b: any)
120120
}
121121

122122
const random_shuffle = shuffle(arr);
123+
123124
for (let i = 0; i < random_shuffle.length - 1; i++) {
124125
if (equalityTest(random_shuffle[i], random_shuffle[i + 1])) {
125126
// neighbors are equal, pick a new random neighbor to swap (not the first or last element, to avoid edge cases)
@@ -128,7 +129,8 @@ export function shuffleNoRepeats(arr: Array<any>, equalityTest: (a: any, b: any)
128129
while (
129130
equalityTest(random_shuffle[i + 1], random_shuffle[random_pick]) ||
130131
equalityTest(random_shuffle[i + 1], random_shuffle[random_pick + 1]) ||
131-
equalityTest(random_shuffle[i + 1], random_shuffle[random_pick - 1])
132+
equalityTest(random_shuffle[i + 1], random_shuffle[random_pick - 1]) ||
133+
equalityTest(random_shuffle[i], random_shuffle[random_pick])
132134
) {
133135
random_pick = Math.floor(Math.random() * (random_shuffle.length - 2)) + 1;
134136
}

packages/jspsych/tests/randomization/randomization.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,29 @@ describe("shuffleNoRepeats", function () {
147147
}
148148
expect(repeats).toBe(0);
149149
});
150+
151+
test("should generate a random order with no repeats using objects", function () {
152+
var equalityTest = (a, b) => a.color === b.color || a.word === b.word;
153+
var toShuffle = [
154+
{ color: "red", word: "red" },
155+
{ color: "red", word: "blue" },
156+
{ color: "blue", word: "blue" },
157+
{ color: "blue", word: "red" },
158+
{ color: "green", word: "green" },
159+
{ color: "green", word: "yellow" },
160+
{ color: "yellow", word: "yellow" },
161+
{ color: "yellow", word: "green" },
162+
];
163+
var repeated = repeat(toShuffle, 20);
164+
var randomOrder = shuffleNoRepeats(repeated, equalityTest);
165+
var repeats = 0;
166+
for (var i = 1; i < randomOrder.length; i++) {
167+
if (equalityTest(randomOrder[i], randomOrder[i - 1])) {
168+
repeats++;
169+
}
170+
}
171+
expect(repeats).toBe(0);
172+
});
150173
});
151174

152175
describe("randomInt", () => {

0 commit comments

Comments
 (0)