Feeding Array to a Classifier - javascript

I have an issue looping through an array using a bayesian classifier function.
Here is my array:
var data = ['good', {
dry: 1,
wet: 0,
moist:0
}, 'bad', {
dry: 0,
wet: 1,
moist: 1
}, 'neutral', {
dry: 1,
wet: 1,
moist:1
}, 'good', {
dry: 1,
wet: 0,
moist: 1
}];
Here's my classifier function:
class Bayes{
constructor(...categories) {
this.categories = {};
this.categoryCounts = {};
categories.forEach(category => {
this.categories[category] = {};
this.categoryCounts[category] = 0;
});
}
train(category, dataset) {
this.categoryCounts[category]++;
Object.keys(dataset).forEach(key => {
this.categories[category][key] = (this.categories[category][key] || '') + dataset[key];
});
};
classify(dataset) {
let scores = {};
let trainingCount = Object.values(this.categoryCounts).reduce((a, b) => a + b );
Object.keys(this.categories).forEach(category => {
scores[category] = 0;
let categoryWords = this.categories[category];
let total = Object.values(categoryWords).reduce((a, b) => a + b );
Object.keys(dataset).forEach(function (key) {
let value = dataset[key];
let s = categoryWords[key] || 0.1;
let i = 0;
while(i<value){
scores[category] += Math.log(s / parseFloat(total));
i++;
}
});
let s = this.categoryCounts[category] || 0.1;
scores[category] = (s / trainingCount);
});
return scores;
};
};
Normally, to classify the data; I'll do:
var b = new Bayes('good', 'bad', 'neutral');
b.train('good', { dry: 1, wet: 0, moist:0});
b.train('bad', {dry: 0,wet: 1,moist: 1});
b.train('neutral', {dry: 1,wet: 1,moist:1});
b.train('good', {dry: 1,wet: 0,moist: 1});
console.log(b.classify({ dry: 0, wet: 1, moist: 1}));
// good: 0.5, bad: 0.25, neutral: 0.25
But when I can't figure out how to train the data by iterating through data.
I need help to feed the array dynamically as a javascript object.

if you can guarantee the data structure consistency, such as
let data = [key, value, key, value, key, value......]
const data = ['good', { dry: 1, wet: 0, moist:0}, 'neutral', {dry: 1,wet: 1,moist:1}, 'good', {dry: 1,wet: 0,moist: 1}];
// 1: chunk it
const size = 2;
const chunks = [];
while (data.length) {
chunks.push(data.splice(0, size));
}
console.log(chunks);
// 2: loop through your train
let keys = chunks.map(val=>val[0])
let deDupeKeys = [...new Set(keys)]
console.log(keys)
console.log(deDupeKeys)
// var b = new Bayes(deDupeKeys)
chunks.forEach(chunk => {
console.log(chunk[0])
console.log(chunk[1])
// b.train(chunk[0],chunk[1]);
})

Assuming the data array will have the format: data = [category, dataset, category, dataset...], a simple solution would be to loop the data array as follows and train the classifier.
for (let i = 0; i < data.length; i = i + 2) {
console.log("category : ", data[i], "dataset : ", data[i + 1]);
b.train(data[i], data[i + 1]);
}

Related

Combine arrays inside map according to label and sum data

I have an array with some streaming channel data, according to the shift (Morning and Afternoon).
I spent the night trying some functions like reduce, but I couldn't understand how it works and stagnated.
var array = [{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"55.00"},{"Outro":"20.00"}]},{"label":"manha","data":[{"Amazon Prime":"50.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"25.00"},{"Outro":"0.00"}]},{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"50.00"},{"Outro":"0.00"}]},{"label":"tarde","data":[{"Amazon Prime":"10.00"},{"AppleTV":"11.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"9.00"},{"Outro":"20.00"}]},{"label":"tarde","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"5.00"},{"Nenhuma":"25.00"},{"Netflix":"20.00"},{"Outro":"50.00"}]}]
I expect to have this output:
The sum total of all streaming channels, divided by the amount of objects value per shift (morning and afternoon)
[{"label":"manha","data":[{"Amazon Prime":"16.66"},{"AppleTV":"0.00"},{"HBO Max":"16.66"},{"Nenhuma":"16.66"},{"Netflix":"43.33"},{"Outro":"6.66"}]},{"label":"tarde","data":[{"Amazon Prime":"5.00"},{"AppleTV":"5.50"},{"HBO Max":"2.50"},{"Nenhuma":"36.00"},{"Netflix":"14.50"},{"Outro":"35.00"}]}]
I would be very grateful if you could help me, and if possible, explain.
Let's solve this problem in steps.
The first attempt is using reduce to iterate through the result and build something.
For simplicity let's get it to build an object where the keys represents the labels.
The reason for this is we can use this key to merge similar keys together.
On the TODO we observe that:
The numerical values are strings not number and do not lend itself for arithmetic operations
The subarray is difficult to merge and could do with a conversion to object as well
let array = [{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"55.00"},{"Outro":"20.00"}]},{"label":"manha","data":[{"Amazon Prime":"50.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"25.00"},{"Outro":"0.00"}]},{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"50.00"},{"Outro":"0.00"}]},{"label":"tarde","data":[{"Amazon Prime":"10.00"},{"AppleTV":"11.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"9.00"},{"Outro":"20.00"}]},{"label":"tarde","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"5.00"},{"Nenhuma":"25.00"},{"Netflix":"20.00"},{"Outro":"50.00"}]}];
let result = array.reduce( function (p, c, i, a) {
let label = c.label;
if (!(label in p)) {
p[label] = c.data;
}
return p;
}, { } );
console.log(JSON.stringify(result, undefined, 2));
// Output:
// {
// "manha": [ { "Amazon Prime": "0.00" },
// { "AppleTV": "0.00" },
// { "HBO Max": "25.00" },
// { "Nenhuma": "0.00" },
// { "Netflix": "55.00" },
// { "Outro": "20.00" }
// ],
// "tarde": [ { "Amazon Prime": "10.00" },
// { "AppleTV": "11.00" },
// { "HBO Max": "0.00" },
// { "Nenhuma": "50.00" },
// { "Netflix": "9.00" },
// { "Outro": "20.00" }
// ]
// }
For the second attempt, we will:
convert more arrays to objects
as an object we can make use of object methods such as in to determine whether a key exists or not
we can use parseFloat to convert strings to numbers
we can start collating the information together
This produces a nice set of raw data.
let array = [{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"55.00"},{"Outro":"20.00"}]},{"label":"manha","data":[{"Amazon Prime":"50.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"25.00"},{"Outro":"0.00"}]},{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"50.00"},{"Outro":"0.00"}]},{"label":"tarde","data":[{"Amazon Prime":"10.00"},{"AppleTV":"11.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"9.00"},{"Outro":"20.00"}]},{"label":"tarde","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"5.00"},{"Nenhuma":"25.00"},{"Netflix":"20.00"},{"Outro":"50.00"}]}];
let result = array.reduce( function (p, c, i, a) {
let label = c.label;
if (!(label in p)) {
p[label] = { };
}
for (let i = 0; i < c.data.length; i++) {
let e = Object.entries(c.data[i]);
let k = e[0][0];
let v = parseFloat(e[0][1]);
if (!(k in p[label])) {
p[label][k] = [ ];
}
p[label][k].push(v);
}
return p;
}, { } );
console.log(JSON.stringify(result, undefined, 2));
// Output:
// {
// "manha": {
// "Amazon Prime": [ 0, 50, 0 ],
// "AppleTV": [ 0, 0, 0 ],
// "HBO Max": [ 25, 25, 0 ],
// "Nenhuma": [ 0, 0, 50 ],
// "Netflix": [ 55, 25, 50 ],
// "Outro": [ 20, 0, 0 ]
// },
// "tarde": {
// "Amazon Prime": [ 10, 0 ],
// "AppleTV": [ 11, 0 ],
// "HBO Max": [ 0, 5 ],
// "Nenhuma": [ 50, 25 ],
// "Netflix": [ 9, 20 ],
// "Outro": [ 20, 50 ]
// }
// }
For the final step, we just average out the remaining array and convert the numerical result back to a string.
let array = [{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"55.00"},{"Outro":"20.00"}]},{"label":"manha","data":[{"Amazon Prime":"50.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"25.00"},{"Outro":"0.00"}]},{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"50.00"},{"Outro":"0.00"}]},{"label":"tarde","data":[{"Amazon Prime":"10.00"},{"AppleTV":"11.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"9.00"},{"Outro":"20.00"}]},{"label":"tarde","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"5.00"},{"Nenhuma":"25.00"},{"Netflix":"20.00"},{"Outro":"50.00"}]}];
let tmp = array.reduce( function (p, c, i, a) {
let label = c.label;
if (!(label in p)) {
p[label] = { };
}
for (let i = 0; i < c.data.length; i++) {
let e = Object.entries(c.data[i]);
let k = e[0][0];
let v = parseFloat(e[0][1]);
if (!(k in p[label])) {
p[label][k] = [ ];
}
p[label][k].push(v);
}
return p;
}, { } );
let result = Object.entries(tmp).map( ( [label, _data] ) => (
{ label : label,
data: Object.entries(_data).map( function ( [k, v] ) {
let obj = { };
obj[k] = ( v.reduce( (p,c) => p + c ) / v.length ).toFixed(2);
return obj;
} )
}
) );
console.log(JSON.stringify(result, undefined, 2));
// Output:
// [
// {
// "label": "manha",
// "data": [
// { "Amazon Prime": "16.67" },
// { "AppleTV": "0.00" },
// { "HBO Max": "16.67" },
// { "Nenhuma": "16.67" },
// { "Netflix": "43.33" },
// { "Outro": "6.67" }
// ]
// },
// {
// "label": "tarde",
// "data": [
// { "Amazon Prime": "5.00" },
// { "AppleTV": "5.50" },
// { "HBO Max": "2.50" },
// { "Nenhuma": "37.50" },
// { "Netflix": "14.50" },
// { "Outro": "35.00" }
// ]
// }
// ]
Some final remarks on this answer compared to the question supplied.
I used toFixed(2) which implements a round up
Answers show "16.67" instead of "16.66" for the "manha" averages
For the "tarde" I got "37.50" ( i.e. (50 + 25) / 2 === 37.50 ) instead of "36.00"
All other values shown in the output matches to what is being requested in the question
This is probably a bit longer then what you have hoped for but it should work.
let newAr = []
for(el of array) {
const currentLabel = el.label
let indexOfLabel = -1
for(let i = 0; i < newAr.length; ++i) {
if(newAr[i].label === currentLabel) indexOfLabel = i
}
if(indexOfLabel >= 0) {
for(let i = 0; i < el.data.length; ++i) {
const key = Object.keys(el.data[i])
newAr[indexOfLabel].data[i][key] = parseInt(newAr[indexOfLabel].data[i][key])
newAr[indexOfLabel].data[i][key] += parseInt(el.data[i][key])
}
} else {
newAr.push(el)
}
}
const occurrences = array.reduce(function (acc, curr) {
return acc[curr.label] ? ++acc[curr.label] : acc[curr.label] = 1, acc
}, {});
for(el of newAr) {
for(data of el.data) {
data[Object.keys(data)] = (data[Object.keys(data)] / occurrences[el.label]).toFixed(2)
}
}
Another approach. I simply used hash grouping twice to create an intermediate object and create a final object at the end
const data = [{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"55.00"},{"Outro":"20.00"}]},{"label":"manha","data":[{"Amazon Prime":"50.00"},{"AppleTV":"0.00"},{"HBO Max":"25.00"},{"Nenhuma":"0.00"},{"Netflix":"25.00"},{"Outro":"0.00"}]},{"label":"manha","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"50.00"},{"Outro":"0.00"}]},{"label":"tarde","data":[{"Amazon Prime":"10.00"},{"AppleTV":"11.00"},{"HBO Max":"0.00"},{"Nenhuma":"50.00"},{"Netflix":"9.00"},{"Outro":"20.00"}]},{"label":"tarde","data":[{"Amazon Prime":"0.00"},{"AppleTV":"0.00"},{"HBO Max":"5.00"},{"Nenhuma":"25.00"},{"Netflix":"20.00"},{"Outro":"50.00"}]}]
const groups = data.reduce((acc, { label, data }) => {
acc[label] ??= {};
data.forEach((item) => {
const [[channel, value]] = Object.entries(item);
acc[label][channel] ??= [];
acc[label][channel].push(Number(value));
});
return acc;
}, {});
// groups
//
// {"manha": {
// "Amazon Prime": [0, 50, 0"],
// "AppleTV": [0, 0, 0],
// "HBO Max": [25, 25, 0],
// "Nenhuma": [0, 0, 50],
// "Netflix": [55, 25,50],
// "Outro": [20, 0, 0]},
// ...}
const getFixedAvg = (data) => {
const average = data.reduce((avg, e) => avg + e) / data.length;
return (Math.floor(average * 100) / 100) // fix 16.67 to 16.66
.toFixed(2);
};
const makeData = (dataObj) => Object.entries(dataObj)
.map(([channel, dataValues]) => ({ [channel]: getFixedAvg(dataValues) }));
const result = Object.entries(groups)
.map(([label, dataObj]) => ({ label, data: makeData(dataObj) }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0 }

How to compare two arrays and return another one?

How to compare two arrays and return another one?
I'm trying to compare two arrays to compare records by id and then render a new array
const arr1 = [
{ id: 1, title: "Admin" },
{ id: 2, title: "Vip" }
];
const arr2 = [
{
id: 1,
root: 1
},
{
id: 2,
root: 0
}
];
let intersection = arr1.filter(({ id }) => arr2.includes(id));
need:
const needArr = [
{ id: 1, title: "Admin", root: 1 },
{ id: 2, title: "Vip", root: 0 }
];
You could make use of map() and find() and iterate over the first array arr1:
const needArr = arr1.map(entry => {
const root = arr2.find(arr2Entry => entry.id === arr2Entry.id)?.root
return {...entry, root: root}
} )
The root property will be set to undefined for each entry in the needArr result if there is no entry with the same id in arr2 as in arr1.
Something like this could work,
const giveNew = (a, b) => {
let shorter, longer;
if(a.length>b.length){
longer = a;
shorter = b;
} else {
longer = b;
shorter = a;
}
return longer.map((v, i)=> {
const matched = shorter.find(val=> val.id === v.id);
if(matched){
return {
...v, ...matched
}
}
})
}
Assuming there's a 1:1 relationship between the arrays - map over one of the arrays, find the corresponding object in the other array by its id, and then return a new updated object.
const arr1=[{id:1,title:"Admin"},{id:2,title:"Vip"}],arr2=[{id:1,root:1},{id:2,root:0}];
const out = arr2.map(obj => {
return {
...arr1.find(inner => inner.id === obj.id),
root: obj.root
};
});
console.log(out);
As is pointed out in Merge two array of objects based on a key, you can do this:
let intersection = arr1.map(item => ({...item, ...arr2.find(item2 => item.id === item2.id)}));
I tried this worked.
const arr1 = [
{ id: 1, title: "Admin" },
{ id: 2, title: "Vip"}
];
const arr2 = [
{
id: 1,
root: 1
},
{
id: 2,
root: 0
}
];
for(var i=0 ;i < arr2.length; i++)
{
objIndex = arr1.findIndex((obj => obj.id == arr2[i].id));
arr1[objIndex].root = arr2[i].root;
}
console.log(arr1);
Hope this satisfies your use case. This also works in the case where there is no 1:1 mappings.
const arr1 = [
{ id: 1, title: "Admin" , root: 0 },
{ id: 2, title: "Vip" , root: 0 },
{ id: 100, title: "NotExistInArr2" , root: 0 }
];
const arr2 = [
{
id: 1,
root: 1
},
{
id: 2,
root: 0
},
{
id: 200,
root: 0
}
];
const consolidatedIds = arr1.map(a => a.id).concat(arr2.map(a => a.id));
//console.log(consolidatedIds);
const consolidatedDedupedIds = arrayUnique(consolidatedIds);
//console.log(consolidatedDedupedIds);
const needArr = consolidatedDedupedIds.map(entry => {
const arr1Item = arr1.find(arr1Entry => entry === arr1Entry.id);
const arr2Item = arr2.find(arr2Entry => entry === arr2Entry.id);
return {...arr1Item, ...arr2Item}
} )
console.log(needArr)
//--- utility function
function arrayUnique(array) {
var a = array.concat();
for(var i=0; i<a.length; ++i) {
for(var j=i+1; j<a.length; ++j) {
if(a[i] === a[j])
a.splice(j--, 1);
}
}
return a;
}
Note: improvised version of other questions, inspired from other answers

How do I randomly select an object from an array multiple times and store each in an array?

I am trying to pull an object out of an array of objects using a function that randomizes the object selected based on some rules I preset (each object has an upper and lower bound from 0 to 1 which controls its "chances" of being selected.
I want to run this function multiple times and store the result of each separate call in a new array.
Below is the code I wrote. It generates the prescribed number of different objects, however the portion where I try to build the array of those is instead just pushing multiple of the same call into the array so I end up with an array full of the same object I randomly pulled.
const animals = [
{
upperProb: 1,
lowerProb: 0.8,
Animal: 'Zebra'
},
{
upperProb: 0.8,
lowerProb: 0.25,
Animal: 'Cat'
},
{
upperProb: 0.25,
lowerProb: 0,
Animal: 'Narwhal'
},
];
const generatedAnimal = {};
let animalChoice = () => {
const numGen = Math.random();
console.log(numGen);
const selectedAnimal = animals.find(animal =>
animal.upperProb > numGen
&& animal.lowerProb <= numGen
);
generatedAnimal.Animal = selectedAnimal.Animal;
return generatedAnimal;
};
console.log(generatedAnimal);
const generateDist = () => {
let animalDist = [];
let i = 0;
do {
animalChoice();
animalDist.push(generatedAnimal);
console.log(generatedAnimal);
i++
} while (i < 10)
console.log(animalDist);
}
generateDist();
Your code is almost correct. You are pushing the same reference to your array multiple times and thus getting the ref 2 output. You are also making generatedAnimal a constant when it should be a variable. Easy to fix, see code below:
const animals = [
{
upperProb: 1,
lowerProb: 0.8,
Animal: 'Zebra'
},
{
upperProb: 0.8,
lowerProb: 0.25,
Animal: 'Cat'
},
{
upperProb: 0.25,
lowerProb: 0,
Animal: 'Narwhal'
},
];
/*********change this**********************
const generatedAnimal = {};
**************to***************************/
var generatedAnimal = {};
let animalChoice = () => {
const numGen = Math.random();
//console.log(numGen);
const selectedAnimal = animals.find(animal =>
animal.upperProb > numGen
&& animal.lowerProb <= numGen
);
generatedAnimal.Animal = selectedAnimal.Animal;
return generatedAnimal;
};
//console.log(generatedAnimal);
const generateDist = () => {
let animalDist = [];
let i = 0;
do {
/**********add this************/
generatedAnimal={};
/******************************/
animalChoice();
animalDist.push(generatedAnimal);
//console.log(generatedAnimal);
i++
} while (i < 10)
console.log(animalDist);
}
generateDist();

How to convert an unorganized array into an grouped array by id

I'm trying to create an array that contains objects with an id and amount, grouped by id. The ids needs to be unique. So if there is 2 objects with same id, the amount will be added.
I can do it with nested for-loops, but I find this solution inelegant and huge. Is there a more efficient or cleaner way of doing it?
var bigArray = [];
// big Array has is the source, it has all the objects
// let's give it 4 sample objects
var object1 = {
id: 1,
amount: 50
}
var object2 = {
id: 2,
amount: 50
}
var object3 = {
id: 1,
amount: 150
}
var object4 = {
id: 2,
amount:100
}
bigArray.push(object1,object2,object3,object4);
// organizedArray is the array that has unique ids with added sum. this is what I'm trying to get
var organizedArray = [];
organizedArray.push(object1);
for(var i = 1; i < bigArray.length; i++ ) {
// a boolean to keep track whether the object was added
var added = false;
for (var j = 0; j < organizedArray.length; j++){
if (organizedArray[j].id === bigArray[i].id) {
organizedArray[j].amount += bigArray[i].amount;
added = true;
}
}
if (!added){
// it has object with new id, push it to the array
organizedArray.push(bigArray[i]);
}
}
console.log(organizedArray);
You can definitly make it cleaner and shorter by using reduce, not sure about efficiency though, i would say a traditional for loop is more efficient :
var bigArray = [];
var object1 = {id: 1, amount: 50}
var object2 = {id: 2, amount: 50}
var object3 = {id: 1, amount: 150}
var object4 = {id: 2, amount: 100}
bigArray.push(object1, object2, object3, object4);
var organizedArray = bigArray.reduce((acc, curr) => {
// check if the object is in the accumulator
const ndx = acc.findIndex(e => e.id === curr.id);
if(ndx > -1) // add the amount if it exists
acc[ndx].amount += curr.amount;
else // push the object to the array if doesn't
acc.push(curr);
return acc;
}, []);
console.log(organizedArray)
Rather than an organized array, how about a single object whose keys are the ids and values are the sums.
var bigArray = [
{ id: 1, amount: 50 },
{ id: 2, amount: 50 },
{ id: 1, amount: 150 },
{ id: 2, amount: 100 }
];
let total = {}
bigArray.forEach(obj => {
total[obj.id] = (total[obj.id] || 0) + obj.amount;
});
console.log(total);
If you really need to convert this to an array of objects then you can map the keys to objects of your choosing like this:
var bigArray = [
{ id: 1, amount: 50 },
{ id: 2, amount: 50 },
{ id: 1, amount: 150 },
{ id: 2, amount: 100 }
];
let total = {}
bigArray.forEach(obj => {
total[obj.id] = (total[obj.id] || 0) + obj.amount;
});
console.log(total);
// If you need the organized array:
let organizedArray = Object.keys(total).map(key => ({ id: key, amount: total[key] }));
console.log(organizedArray);
function getUniqueSums(array) {
const uniqueElements = [];
const arrayLength = array.length;
for(let index = 0; index < arrayLength; index++) {
const element = array[index];
const id = element.id;
const uniqueElement = findElementByPropertyValue(uniqueElements, 'id', id);
if (uniqueElement !== null) {
uniqueElement.amount += element.amount;
continue;
}
uniqueElements.push(element);
}
return uniqueElements;
}
function findElementByPropertyValue(array, property, expectedValue) {
const arrayLength = array.length;
for(let index = 0; index < arrayLength; index++) {
const element = array[index];
const value = element[property];
if (value !== expectedValue) {
continue;
}
return element;
}
return null;
}
This is an untested code. You will be able to understand the logic. Logic is almost same yours. But, perhaps a more readable code.

how to count duplicate values object to be a value of object

how to count the value of object in new object values
lets say that i have json like this :
let data = [{
no: 3,
name: 'drink'
},
{
no: 90,
name: 'eat'
},
{
no: 20,
name: 'swim'
}
];
if i have the user pick no in arrays : [3,3,3,3,3,3,3,3,3,3,3,90,20,20,20,20]
so the output should be an array
[
{
num: 3,
total: 11
},
{
num: 90,
total: 1
},
{
num:20,
total: 4
}
];
I would like to know how to do this with a for/of loop
Here is the code I've attempted:
let obj = [];
for (i of arr){
for (j of data){
let innerObj={};
innerObj.num = i
obj.push(innerObj)
}
}
const data = [{"no":3,"name":"drink"},{"no":90,"name":"eat"},{"no":20,"name":"swim"}];
const arr = [3,3,3,3,3,3,3,3,3,3,3,20,20,20,20,80,80];
const lookup = {};
// Loop over the duplicate array and create an
// object that contains the totals
for (let el of arr) {
// If the key doesn't exist set it to zero,
// otherwise add 1 to it
lookup[el] = (lookup[el] || 0) + 1;
}
const out = [];
// Then loop over the data updating the objects
// with the totals found in the lookup object
for (let obj of data) {
lookup[obj.no] && out.push({
no: obj.no,
total: lookup[obj.no]
});
}
document.querySelector('#lookup').textContent = JSON.stringify(lookup, null, 2);
document.querySelector('#out').textContent = JSON.stringify(out, null, 2);
<h3>Lookup output</h3>
<pre id="lookup"></pre>
<h3>Main output</h3>
<pre id="out"></pre>
Perhaps something like this? You can map the existing data array and attach filtered array counts to each array object.
let data = [
{
no: 3,
name: 'drink'
},
{
no:90,
name: 'eat'
},
{
no:20,
name: 'swim'
}
]
const test = [3,3,3,3,3,3,3,3,3,3,3,90,20,20,20,20]
const result = data.map((item) => {
return {
num: item.no,
total: test.filter(i => i === item.no).length // filters number array and then checks length
}
})
You can check next approach using a single for/of loop. But first I have to create a Set with valid ids, so I can discard noise data from the test array:
const data = [
{no: 3, name: 'drink'},
{no: 90, name: 'eat'},
{no: 20, name: 'swim'}
];
const userArr = [3,3,3,3,3,3,3,3,7,7,9,9,3,3,3,90,20,20,20,20];
let ids = new Set(data.map(x => x.no));
let newArr = [];
for (i of userArr)
{
let found = newArr.findIndex(x => x.num === i)
if (found >= 0)
newArr[found].total += 1;
else
ids.has(i) && newArr.push({num: i, total: 1});
}
console.log(newArr);

Categories