How to assign and iterate only once over array?
Solution 1:
It's a good practice, when you hear "random without duplicates", to think "shuffle".
So to assign random, non-repeating, correctly gendered avatars, segregate the avatars by gender, shuffle the male and female avatars, then assign them sequentially to users....
const avatars = getAvatars(); // just to move the data to the bottom of the snippet
const users = getUsers();
const shuffledMales = shuffle(avatars.filter(a => a.gender==="male"));
const shuffledFemales = shuffle(avatars.filter(a => a.gender==="female"));
let maleIndex = 0, femaleIndex = 0;
users.forEach(user => {
user.avatar = user.gender === "male" ? shuffledMales[maleIndex++] : shuffledFemales[femaleIndex++];
});
console.log(users);
// fisher-yates shuffle, adapted from https://bost.ocks.org/mike/shuffle/
function shuffle(array) {
let copy = [],
n = array.length,
i;
while (n) {
let i = Math.floor(Math.random() * array.length);
if (i in array) {
copy.push(array[i]);
delete array[i];
n--;
}
}
return copy;
}
function getAvatars() {
return [{
"id": 1,
"image": "maleavatar1",
"gender": "male"
},
{
"id": 2,
"image": "maleavatar2",
"gender": "male"
},
{
"id": 3,
"image": "maleavatar3",
"gender": "male"
},
{
"id": 4,
"image": "femaleavatar1",
"gender": "female"
},
{
"id": 5,
"image": "femaleavatar2",
"gender": "female"
},
{
"id": 6,
"image": "femaleavatar3",
"gender": "female"
},
{
"id": 7,
"image": "femaleavatar4",
"gender": "female"
},
];
}
function getUsers() {
return [{
"id": 1,
"name": "Manila",
"gender": "female"
},
{
"id": 2,
"name": "Josy",
"gender": "female"
},
{
"id": 3,
"name": "Eliza",
"gender": "female"
},
{
"id": 4,
"name": "Martin",
"gender": "male"
},
{
"id": 5,
"name": "Mark",
"gender": "male"
},
{
"id": 6,
"name": "John",
"gender": "male"
}
];
}