duplicate player name should not be in the same array - javascript

I am making a matchmaking system where 2 players of the same level will be matched.
My target is how can I remove a duplicate player name in the same
array? After removing that duplicate entry, it should be stored on
another array(waiting list).
I have provided an example and a screenshot below. Any help will be appreciated. Thank you.
script for matching: (Matching the players with the same level)
const combine = (source) => {
return source.reduce((acc, curr) => {
if (acc[curr.level]) {
const levelArr = acc[curr.level];
const last = levelArr[levelArr.length - 1];
if (last.length === 2) {
levelArr.push([curr])
} else {
last.push(curr)
}
} else {
acc[curr.level] = [
[curr]
];
}
return acc;
}, {})
};
script ajax: (Fetching data from db)
let ajaxResult = []; // the pushed data will be saved here
let save_method;
let table;
let base_url = "<?php echo base_url();?>";
let result = [];
var html = "";
$(document).ready(function() {
//datatables
table = $("#entry_list1").DataTable({
processing: false,
serverSide: true,
order: [],
searching: false,
paging: false,
info: false,
ajax: {
url: "<?php echo site_url('controller/fetch')?>",
type: "POST",
async: true,
dataType: "json",
success: function(data) {
result = combine(data.data2);
console.log(result)
var keys = Object.keys(result)
for (var i = 0; i < keys.length; i++) {
result[keys[i]].forEach(function(val) {
val.forEach(function(value, index) {
var entryIDs = index == 0 ? "entryIDM[]" : "entryIDW[]"
var players = index == 0 ? "playerM[]" : "playerW[]"
var levels = index == 0 ? "levelM[]" : "levelW[]"
html += `<input type="text" name="${entryIDs}" value="${value.entryID}">
<input type="text" name="${players}" value="${value.player}">
<input type="text" name="${levels}" value="${value.level}">
`
})
})
}
document.getElementById("result").innerHTML = html //add html to div
},
},
"columnDefs": [{
"targets": [0], //first column
"orderable": false, //set not orderable
},
{
"targets": [-1], //last column
"orderable": false, //set not orderable
},
],
});
});

I would suggest removing duplicate players before passing them to the combine function. This way you shouldn't see duplicate players matched.
I would create a removeDuplicates function to remove duplicate players from the player list.
In this example, we have 18 players, with each player duplicated once.
We run these through the removeDuplicates function, now we have 9 unique players.
We then pass the unique players to the combine function and get 3 groups of 2 matched players and 3 unmatched players.
const players = Array.from({ length: 18 }, (v,k) => ( { level: Math.floor(k / 6) + 1, player: `test-${Math.floor(k/2)+1}` }));
function removeDuplicates(players) {
return Object.values(players.reduce((acc, curr) => {
acc[curr.player] = acc[curr.player] || curr;
return acc;
}, {}))
}
const combine = (source) => {
return source.reduce((acc, curr) => {
if (acc[curr.level]) {
const levelArr = acc[curr.level];
const last = levelArr[levelArr.length - 1];
if (last.length === 2) {
levelArr.push([curr])
} else {
last.push(curr)
}
} else {
acc[curr.level] = [
[curr]
];
}
return acc;
}, {})
};
console.log("All players:", players);
const uniquePlayers = removeDuplicates(players);
console.log("Unique players:", uniquePlayers);
const matched = Object.values(combine(uniquePlayers)).flatMap(a => a.filter(x => x.length === 2));
const unmatched = Object.values(combine(uniquePlayers)).flatMap(a => a.filter(x => x.length === 1));
console.log("Matched players:", matched);
console.log("Unmatched players:", unmatched);

Related

remove 2 common array item javascript

I have 2 arrays
let arryOne =
[
{
'catRefId' : "200531-2"
},
{
'catRefId' : "201425-1"
},
{
'catRefId' : "201423-1"
},
]
let arryTwo =
[
{
'removeId' : "200531-2"
},
{
'removeId' : "201425-1"
},
]
I tried below code but not working
let _finalArray = [];
for (let index = 0; index < arryOne.length; index++) {
_finalArray = arryOne.filter(obj => obj.catRefId === arryTwo[index].removeId)
}
Here's an approach using Set
let arryTwo = [{ removeId: '200531-2' }, { removeId: '201425-1'}];
let arryOne = [{ catRefId: '200531-2' }, { catRefId: '201425-1'},{ catRefId: '201423-1' }];
const idsToRemove = new Set(arryTwo.map(({ removeId }) => removeId));
const _finalArray = arryOne.filter((item) => !idsToRemove.has(item.catRefId));
console.log(_finalArray);
This is a possible solution:
First we extract the Ids from the second array.
Then we filter all matching references.
What's left is all references not present in arryTwo.
let _finalArray = [];
_finalArray = arryOne.filter(obj => !arryTwo.map(obj => obj.removeId).includes(obj.catRefId));

Node.js - How to merge objects inside an array based on condition?

In Node.js, I have 3 sets of data like
[
{
"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
"dailyData":159392.235451,
"dailyDataInUSC":255.284807
}
]
and
[
{
"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
"monthlyData":159392.235451,
"monthlyDataInUSC":255.284807
},
{
"userId":"23fs6fds3-34k4-17de-3123-d2ec81e8aaf3",
"monthlyData":349392.455451,
"monthlyDataInUSC":655.234807
}
]
and
[
{
"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
"threeMonthsData":159392.235451,
"threeMonthsDataInUSC":255.284807
},
{
"userId":"23fs6fds3-34k4-17de-3123-d2ec81e8aaf3",
"threeMonthsData":349392.455451,
"threeMonthsDataInUSC":655.234807
},
{
"userId":"34sdf34-67j4-54nd-6763-d2ec81e8aaf3",
"threeMonthsData":6789392.455451,
"threeMonthsDataInUSC":905.655807
}
]
How can I combine this to one object based on userId(filter) inside an array.
Eg, output should be like
[
{
"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
"dailyData":159392.235451,
"dailyDataInUSC":255.284807,
"monthlyData":159392.235451,
"monthlyDataInUSC":255.284807,
"threeMonthsData":159392.235451,
"threeMonthsDataInUSC":255.284807
}
]
Please help me to achieve this.
A combination of spread, reduce and findIndex can be used to solve the problem.
Combine the original arrays into a single array using the spread operator.
Use reduce to group the elements by key (in this case userId)
Something like this :
const dailyData = [{"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3","dailyData":159392.235451,"dailyDataInUSC":255.284807}];
const monthlyData = [{"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3","monthlyData":159392.235451,"monthlyDataInUSC":255.284807}, {"userId":"23fs6fds3-34k4-17de-3123-d2ec81e8aaf3","monthlyData":349392.455451,"monthlyDataInUSC":655.234807}]
const triMonthlyData = [{"userId":"54c7f3ef-64d4-40de-8100-d2ec81e8aaf3","threeMonthsData":159392.235451,"threeMonthsDataInUSC":255.284807}, {"userId":"23fs6fds3-34k4-17de-3123-d2ec81e8aaf3","threeMonthsData":349392.455451,"threeMonthsDataInUSC":655.234807}, {"userId":"34sdf34-67j4-54nd-6763-d2ec81e8aaf3","threeMonthsData":6789392.455451,"threeMonthsDataInUSC":905.655807}]
const combinedData = [...dailyData, ...monthlyData, ...triMonthlyData].reduce((mergedResult, curElement) => {
let matchingElementIdx = mergedResult.findIndex(ele => ele.userId === curElement.userId);
if (matchingElementIdx !== -1) {
mergedResult[matchingElementIdx] = {...mergedResult[matchingElementIdx], ...curElement};
} else {
mergedResult = [...mergedResult, curElement];
}
return mergedResult;
}, []);
console.log(combinedData);
const aa = () => {
let aa = [
{
userId: "54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
dailyData: 159392.235451,
dailyDataInUSC: 255.284807
}
];
let bb = [
{
userId: "54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
monthlyData: 159392.235451,
monthlyDataInUSC: 255.284807
},
{
userId: "23fs6fds3-34k4-17de-3123-d2ec81e8aaf3",
monthlyData: 349392.455451,
monthlyDataInUSC: 655.234807
}
];
let cc = [
{
userId: "54c7f3ef-64d4-40de-8100-d2ec81e8aaf3",
threeMonthsData: 159392.235451,
threeMonthsDataInUSC: 255.284807
},
{
userId: "23fs6fds3-34k4-17de-3123-d2ec81e8aaf3",
threeMonthsData: 349392.455451,
threeMonthsDataInUSC: 655.234807
},
{
userId: "34sdf34-67j4-54nd-6763-d2ec81e8aaf3",
threeMonthsData: 6789392.455451,
threeMonthsDataInUSC: 905.655807
}
];
let newArrObj = aa;
bb.forEach(item => {
let index = newArrObj.findIndex(item1 => item1.userId === item.userId);
if (index === -1) {
newArrObj = [...newArrObj, item];
} else {
newArrObj[index] = { ...newArrObj[index], ...item };
}
});
cc.forEach(item => {
let index = newArrObj.findIndex(item1 => item1.userId === item.userId);
if (index === -1) {
newArrObj = [...newArrObj, item];
} else {
newArrObj[index] = { ...newArrObj[index], ...item };
}
});
console.log(newArrObj);
};

array of strings into array of objects with one attribute each?

How can I turn the below array
['12345', '83747']
into the below array of objects
[ {'id': '12345'}, {'id': '83747'} ]
using map?
My attempt so far, iDs is an empty array, chunk is an array of string.:
obj.iDs.concat(
chunk.map((item) => ({
id: item,
})),
);
An example, my IDE reports no issues with this code:
const body = [{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'},{'id':'1234'}]
const batchGetRequestObj = {
ids: [],
targetProperties: ['contentID, updateDateTime'],
};
function func() {
try {
chunkArray(
body.map((item) => {
return item.id;
}),
25,
).forEach((chunk) => {
batchGetRequestObj.ids.concat(
chunk.map((item) => ({
ids: item,
})),
);
console.log(batchGetRequestObj);
});
} catch (e) {
console.log(e);
}
}
function chunkArray(array: string[], size: number) {
const slicedArray = [];
for (let i = 0; i < array.length; i += size) {
slicedArray.push(array.slice(i, i + size));
}
return slicedArray;
}
Link to typescript playground
You're using concat, which doesn't mutate the arrays - you'll have to set the values back to the variable
var arr = ['12345', '83747']
var newids = obj.ids.concat(arr.map( str => { return {"id" : str}});
obj.ids = newids

Dynamically splitting strings with multiple keywords

I'm working on headless CMS using Angular.
In the content below, whatever is wrapped inside {{ }} is considered to be an anchor link.
We processes your data in accordance with the {{policy_placeholder}}. You have the right to object to the processing of your personal data. Check “Your rights” in the {{policy_placeholder}} and {{term_policy}} for more information.;`
So with the above example, below is the expected result
[
{
type: "TEXT",
content: "We processes your data in accordance with the "
},
{
type: "LINK",
content: "{{policy_placeholder}}"
},
{
type: "TEXT",
content:
". You have the right to object to the processing of your personal data. Check “Your rights” in the "
},
{
type: "LINK",
content: "{{policy_placeholder}}"
},
{
type: "TEXT",
content: " and "
},
{
type: "LINK",
content: "{{terms_placeholder}}"
},
{
type: "TEXT",
content: " for more information."
}
];
Below is what I tried
splitString = function(string, splitters) {
var list = [string];
for(var i=0, len=splitters.length; i<len; i++) {
traverseList(list, splitters[i], 0);
}
const x = flatten(list);
console.log(x);
return flatten(list);
}
traverseList = function(list, splitter, index) {
if(list[index]) {
if((list.constructor !== String) && (list[index].constructor === String))
(list[index] != list[index].split(splitter)) ? list[index] = list[index].split(splitter) : null;
(list[index].constructor === Array) ? traverseList(list[index], splitter, 0) : null;
(list.constructor === Array) ? traverseList(list, splitter, index+1) : null;
}
}
flatten = function(arr) {
return arr.reduce(function(acc, val) {
return acc.concat(val.constructor === Array ? flatten(val) : val);
},[]);
}
var splitList = ["{{policy_placeholder}}", "{{term_policy}}"];
splitString(source, splitList);
The issue is that I've to manually add the splitList, but i want to make it dynamic based on {{ }}
How can this be done?
When you spread a string, you actually split it into characters.
const source = `We processes your data in accordance with the {{policy_placeholder1}}. You have the right to object to the processing of your personal data. Check “Your rights” in the {{policy_placeholder2}} for more information.`;
function splitString(str) {
const ans = [];
const linkTokenRegex = /\{\{.+?\}\}/g;
const textsArr = str.split(linkTokenRegex);
const linksArr = str.match(linkTokenRegex);
textsArr.forEach((textPart, index) => {
ans.push({
type: "TEXT",
content: textPart,
});
if (linksArr[index]) {
ans.push({
type: "LINK",
content: linksArr[index],
});
}
});
return ans;
}
console.log(splitString(source));

Reformatting array of arrays to nested json in Javascript [duplicate]

I have an array like
[
"parent1|child1|subChild1",
"parent1|child1|subChild2",
"parent|child2|subChild1",
"parent1|child2|subChild2",
"parent2|child1|subChild1",
"parent2|child1|subChild2",
"parent2|child2|subChild1",
.
.
.
]
Wherein my first string before | is the parent and the second string before | is the child and the third string after the second | is the subchild
How can I convert this array into an object like
[
{
"id": "parent1",
"children":[
{
"id": "child1",
"children":[
{
"id": "subChild1"
}
]
}
]
}
]
Parent -> child -> subchild object
Based on Sebastian's answer I tried below using typescript
private genTree(row) {
let self = this;
if (!row) {
return;
}
const [parent, ...children] = row.split('|');
if (!children || children.length === 0) {
return [{
id: parent,
children: []
}];
}
return [{
id: parent,
children: self.genTree(children.join('|'))
}];
}
private mergeDeep(children) {
let self = this;
const res = children.reduce((result, curr) => {
const entry = curr;
const existing = result.find((e) => e.id === entry.id);
if (existing) {
existing.children = [].concat(existing.children, entry.children);
} else {
result.push(entry);
}
return result;
}, []);
for (let i = 0; i < res.length; i++) {
const entry = res[i];
if (entry.children && entry.children.length > 0) {
entry.children = self.mergeDeep(entry.children);
}
};
return res;
}
private constructTree(statKeyNames){
let self = this;
const res = this.mergeDeep(statKeyNames.map(self.genTree).map(([e]) => e));
console.log(res);
}
but this gives me:
Cannot read property 'genTree' of undefined" error
Update:
As per Sebastian's comment changed self.genTree to this.genTree.bind(this) and it worked without any issues
You could use a mapper object which maps each object to it's unique path (You could map the object with each id, but id is not unique here). Then reduce each partial item in the array. Set the root object as the initialValue. The accumulator will be the parent object for the current item. Return the current object in each iteration.
const input = [
"parent1|child1|subChild1",
"parent1|child1|subChild2",
"parent1|child2|subChild1",
"parent1|child2|subChild2",
"parent2|child1|subChild1",
"parent2|child1|subChild2",
"parent2|child2|subChild1"
],
mapper = {},
root = { children: [] }
for (const str of input) {
let splits = str.split('|'),
path = '';
splits.reduce((parent, id, i) => {
path += `${id}|`;
if (!mapper[path]) {
const o = { id };
mapper[path] = o; // set the new object with unique path
parent.children = parent.children || [];
parent.children.push(o)
}
return mapper[path];
}, root)
}
console.log(root.children)
You have to use recursion for that. Take a look here:
const arr = [
"parent1|child1|subChild1",
"parent1|child1|subChild2",
"parent|child2|subChild1",
"parent1|child2|subChild2",
"parent2|child1|subChild1",
"parent2|child1|subChild2",
"parent2|child2|subChild1"
];
function genTree(row) {
const [parent, ...children] = row.split('|');
if (!children || children.length === 0) {
return [{
id: parent,
children: []
}];
}
return [{
id: parent,
children: genTree(children.join('|'))
}];
};
function mergeDeep(children) {
const res = children.reduce((result, curr) => {
const entry = curr;
const existing = result.find((e) => e.id === entry.id);
if (existing) {
existing.children = [].concat(existing.children, entry.children);
} else {
result.push(entry);
}
return result;
}, []);
for (let i = 0; i < res.length; i++) {
const entry = res[i];
if (entry.children && entry.children.length > 0) {
entry.children = mergeDeep(entry.children);
}
};
return res;
}
const res = mergeDeep(arr.map(genTree).map(([e]) => e));
console.log(JSON.stringify(res, false, 2));
I used two helpers here: genTree(row) which recursively generates a simple tree from each row, and mergeDeep(children) which reduces the first-level trees in the result of arr.map(genTree).map(([e]) => e), and then iterates over the array and recursively does the same thing to all children of each entry.

Categories

Resources