'Add another validation to avoid joining the array
I am matchmaking system where 2 players will be matched if they have the same weight. I have my old codes and my new codes. My old codes are working but I have made an adjustment so i improved and changed my code. Now, my target is the same just like my old code.
For this old code, we can see that there's a "noFight" in the array. nofight means, this player should not be matched with the given entryID. For example:
entryID: 1 has a noFight: [2,3], it means that entryID 1 should not be matched with entryID 2 and 3.
const source = [
{
entryID: 1,
entryName: "player1",
weight: 1900,
noFight: [2,3], // changed these to arrays
},
{
entryID: 2,
entryName: "player2",
weight: 1900,
noFight: [1,3,4],
},
{
entryID: 3,
entryName: "player3",
weight: 1900,
noFight: [1,2,4],
},
{
entryID: 4,
entryName: "player4",
weight: 1900,
noFight: [2,3,4],
},
{ // added a new player that will fight anyone to test the logic
entryID: 5,
entryName: "player5",
weight: 1900,
noFight: [],
},
];
function combine(
data = [],
different = 0,
maxGroupSize = 2,
sortedStatement = (a, b) => a.weight - b.weight
) {
const sortedData = [...data].sort(sortedStatement);
const dataGroups = sortedData.reduce((acc, item) => {
const findedAccItem = acc.find(
(accItem) =>
accItem.length < maxGroupSize &&
accItem[0].weight + different >= item.weight &&
!accItem.find((obj) => obj.entryName === item.entryName || item.noFight.includes(obj.entryID)) // here we check if the fighter is in the noFight array or not. I need to add this item.noFight.includes(obj.entryID) validation to my new codes.
);
if (findedAccItem) {
findedAccItem.push(item);
} else {
acc.push([item]);
}
return acc;
}, []);
const namedDataGroups = dataGroups.reduce((acc, item, index) => {
if (item.length > 1) { // and finally we check that there are in fact two fighters in the grouping; without this you'll end up with fighters that didn't get a match in the array as a result of how the reduce above works
const key = [index, ...item.map((item) => item.weight)].join("_");
acc[key] = item;
}
return acc;
}, {});
return namedDataGroups;
}
console.log("Example #1: ", combine(source));
Now in this new code. I cannot achieve my target here. The nofights.
const source = [
{
entryID: 1,
entryName: "player1",
weight: 1900,
noFight: [2,3], // changed these to arrays
},
{
entryID: 2,
entryName: "player2",
weight: 1900,
noFight: [1,3,4],
},
{
entryID: 3,
entryName: "player3",
weight: 1900,
noFight: [1,2,4],
},
{
entryID: 4,
entryName: "player4",
weight: 1900,
noFight: [2,3,4],
},
{ // added a new player that will fight anyone to test the logic
entryID: 5,
entryName: "player5",
weight: 1900,
noFight: [],
},
];
console.log ( combine(source) )
function combine( data = [], different = 0, maxGroupSize = 2 )
{
const
groups = []
, related = []
, sortedData = [...data].sort((a, b) => a.weight - b.weight)
, alreadyInRela = (setX,eName) =>
{
let list = [...setX, eName]
return related.some(rela=>list.every(l=>rela.has(l)))
};
sortedData.forEach((el,indx)=>
{
let place = groups.findIndex( // find a place in a group forEach element, use indx as track
g => g.names.size < maxGroupSize // is the group incomplete ?
&& !g.names.has(el.entryName) // is entryName not in the group list (names Set) ?
&& (el.weight - g.weight) <= different // is the weight falls within the weight range ?
&& !alreadyInRela(g.names, el.entryName ) // is (entryName + group list) does not already used ?
)
if (place < 0) // not found -> create new group
{
let names = new Set().add(el.entryName) // create new group
groups.push( { names, indxs: [indx], weight: el.weight } ) // group constitutive info
related.push( names ) // keep track of group list
}
else // find a place in a group
{
groups[place].names.add(el.entryName) // related list is also updated
groups[place].indxs.push(indx) // add indx to retreive element in sortedData
}
})
return groups.reduce((r,g,i)=> // build result
{
let key = `${i}_` + g.indxs.map(x=>sortedData[x].weight).join('_')
r[key] = []
g.indxs.forEach(x=> r[key].push( sortedData[x]) )
return r
}, {} )
}
Output of my current codes:
{
"0_1900_1900": [
{
"entryID": 1,
"entryName": "player1",
"weight": 1900,
"noFight": [
2,
3
]
},
{
"entryID": 2,
"entryName": "player2",
"weight": 1900,
"noFight": [
1,
3,
4
]
}
],
"1_1900_1900": [
{
"entryID": 3,
"entryName": "player3",
"weight": 1900,
"noFight": [
1,
2,
4
]
},
{
"entryID": 4,
"entryName": "player4",
"weight": 1900,
"noFight": [
2,
3,
4
]
}
],
"2_1900": [
{
"entryID": 5,
"entryName": "player5",
"weight": 1900,
"noFight": []
}
]
}
My target output:
{
"0_1900_1900": [
{
"entryID": 1,
"entryName": "player1",
"weight": 1900,
"noFight": [
2,
3
]
},
{
"entryID": 4,
"entryName": "player4",
"weight": 1900,
"noFight": [
2,
3,
4
]
}
],
"1_1900_1900": [
{
"entryID": 2,
"entryName": "player2",
"weight": 1900,
"noFight": [
1,
3,
4
]
},
{
"entryID": 5,
"entryName": "player5",
"weight": 1900,
"noFight": []
}
]
}
Solution 1:[1]
Your new code is almost identical to old except 2 things:
- noFight isn't checked in new code.
- All groups are used to build result in new code. In old code, only groups of size > 1 are used.
I've made the changes in following snippet.
const source = [
{
entryID: 1,
entryName: "player1",
weight: 1900,
noFight: [2,3], // changed these to arrays
},
{
entryID: 2,
entryName: "player2",
weight: 1900,
noFight: [1,3,4],
},
{
entryID: 3,
entryName: "player3",
weight: 1900,
noFight: [1,2,4],
},
{
entryID: 4,
entryName: "player4",
weight: 1900,
noFight: [2,3,4],
},
{ // added a new player that will fight anyone to test the logic
entryID: 5,
entryName: "player5",
weight: 1900,
noFight: [],
},
];
console.log ( combine(source) )
function combine( data = [], different = 0, maxGroupSize = 2 )
{
const
groups = []
, related = []
, sortedData = [...data].sort((a, b) => a.weight - b.weight)
, alreadyInRela = (setX,eName) =>
{
let list = [...setX, eName]
return related.some(rela=>list.every(l=>rela.has(l)))
};
sortedData.forEach((el,indx)=>
{
let place = groups.findIndex( // find a place in a group forEach element, use indx as track
g => g.names.size < maxGroupSize // is the group incomplete ?
&& !g.names.has(el.entryName) // is entryName not in the group list (names Set) ?
&& (el.weight - g.weight) <= different // is the weight falls within the weight range ?
&& !alreadyInRela(g.names, el.entryName ) // is (entryName + group list) does not already used ?
&& !el.noFight.some(noFightEl => g.indxs.map(gi => sortedData[gi].entryID).includes(noFightEl)) // is el.noFight having any of group item
)
if (place < 0) // not found -> create new group
{
let names = new Set().add(el.entryName) // create new group
groups.push( { names, indxs: [indx], weight: el.weight } ) // group constitutive info
related.push( names ) // keep track of group list
}
else // find a place in a group
{
groups[place].names.add(el.entryName) // related list is also updated
groups[place].indxs.push(indx) // add indx to retreive element in sortedData
}
})
return groups.reduce((r,g,i)=> // build result
{
if (g.indxs.length > 1) {
let key = `${i}_` + g.indxs.map(x=>sortedData[x].weight).join('_')
r[key] = []
g.indxs.forEach(x=> r[key].push( sortedData[x]) )
}
return r
}, {} )
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Avinash Thakur |
