TL;DR I have an array of names that is returned from a network request which I want to shuffle so that the names are in a different order each time the request is made. Additionally, I want to select 6 names from the collection without getting duplicates. I have a CodePen that reproduces the issue, using of instead of Angular's http.get, where I see duplicates in the subsequent selection of groups of 6: https://codepen.io/mcmillhj/pen/rNxNaEB
Problem:
I am working on a small app in Angular that lets you learn your co-worker's names. I make a network request that gets a JSON response that includes names and images for the game. In order to make the game more interesting, and not in the same order each time, I applied the lodash.shuffle operation when the observable is evaluated. I expected this to apply the shuffle operation a single time but I can see it being evaluated every time I request a grouping of 6 people. This leads to the same name appearing in multiple groups. I am sure this is down to me not yet understanding the semantics of these RxJS primitives.
Code:
const { of } = rxjs;
const { map } = rxjs.operators;
const { shuffle } = _;
const getAllPeople = () => {
return of([
"Dorothy Baker",
"Simon Alsop",
"Samantha Coleman",
"Ava May",
"Rachel Quinn",
"Dominic Taylor",
"Donna Stewart",
"Lillian Campbell",
"Katherine Rampling",
"Nathan Sutherland",
"Gabrielle Wilson",
"Amy Hughes",
"Jason Wright",
"Matt Nolan",
"Natalie Hughes",
"Amanda Roberts",
"Megan Parr",
"Una Bell",
"Anthony May",
"Sean Slater",
"Adrian Powell",
"Kimberly Walker",
"Sebastian Black",
"William James"
]).pipe(
map((people) => shuffle(people)),
);
};
const people = getAllPeople();
let cursor = 0;
const getNPeople = (n) => {
const peoplePage = people.pipe(
map((data) => {
const page = data.slice(cursor, n + cursor);
cursor += n;
return page;
})
);
return peoplePage;
};
for (let page = 0; page < 4; page++) {
const ul = document.createElement("ul");
document.body.appendChild(ul);
getNPeople(6).subscribe((people) => {
for (const person of people) {
const li = document.createElement("li");
li.innerText = person;
ul.appendChild(li);
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js"></script>