JS Loop through array based on key values and add values - javascript

I have the following object inside an array:-
[
{"score": 5, "question": 0, "weight": 2},
{"score": 4, "question": 1, "weight": 2},
{"score": 3, "question": 0, "weight": 4},
{"score": 4, "question": 1, "weight": 4},
{"score": 2, "question": 2, "weight": 4},
{"score": 8, "question": 0, "weight": 2}
]
I am trying to loop through the array so I have the following output, so I am able to run some math against the results:-
[
[
{"score": 5, "question": 0, "weight": 2},
{"score": 4, "question": 1, "weight": 2}
],
[
{"score": 3, "question": 0, "weight": 4},
{"score": 4, "question": 1, "weight": 4},
{"score": 2, "question": 2, "weight": 4}
],
[
{"score": 8, "question": 0, "weight": 2}
]
];
Is there a dynamic way I am able to get array1 to look like array2?
I am using flat JS for this please no jQuery answers.
Thanks in advance.
** Note **
Sometimes each section will have more or less values, this is why I require it to be dynamic.

You can do this with reduce() method you just need to keep track of current index for final array.
const data =[
{score: 5, question: 0, weight: 2},
{score: 4, question: 1, weight: 2},
{score: 3, question: 0, weight: 4},
{score: 4, question: 1, weight: 4},
{score: 2, question: 2, weight: 4},
{score: 8, question: 0, weight: 2}
]
const result = data.reduce(function(r, e, i) {
if(i == 0) r = {values: [], counter: 0}
if(e.question == 0 && i != 0) r.counter++
if(!r.values[r.counter]) r.values[r.counter] = [e]
else r.values[r.counter].push(e)
return r;
}, {}).values
console.log(result)

You could check weight and if different, then take a new group.
var data = [{ score: 5, question: 0, weight: 2 }, { score: 4, question: 1, weight: 2 }, { score: 3, question: 0, weight: 4 }, { score: 4, question: 1, weight: 4 }, { score: 2, question: 2, weight: 4 }, { score: 8, question: 0, weight: 2 }],
grouped = data.reduce(function (r, o, i, a) {
if ((a[i - 1] || {}).weight !== o.weight) {
r.push([]);
}
r[r.length - 1].push(o);
return r;
}, []);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You can use Array.reduce() to convert the 1st to the 2nd array. Whenever the current object weight doesn't match lastWeight, add another subarray. Always push the current item to the last subarray:
const arr = [
{score: 5, question: 0, weight: 2},
{score: 4, question: 1, weight: 2},
{score: 3, question: 0, weight: 4},
{score: 4, question: 1, weight: 4},
{score: 2, question: 2, weight: 4},
{score: 8, question: 0, weight: 2}
];
let lastWeight = null;
const result = arr.reduce((r, o) => {
if(lastWeight === null || o.weight !== lastWeight) {
lastWeight = o.weight;
r.push([]);
}
r[r.length - 1].push(o);
return r;
}, []);
console.log(result);

var oldA = [
{"score": 5, "question": 0, "weight": 2},
{"score": 4, "question": 1, "weight": 2},
{"score": 3, "question": 0, "weight": 4},
{"score": 4, "question": 1, "weight": 4},
{"score": 2, "question": 2, "weight": 4},
{"score": 8, "question": 0, "weight": 2}
];
var newA = [];
var prevW = 0;
var prevA;
for (var i = 0; i < oldA.length; i++) {
if (oldA[i].weight != prevW) {
prevA = [];
newA.push(prevA);
prevW = oldA[i].weight;
}
prevA.push(oldA[i]);
}
console.log(newA);

You can use array#reduce to group your array. Check if the value of question is 0 then push a new array and add the object to it.
var data = [ {"score": 5, "question": 0, "weight": 2}, {"score": 4, "question": 1, "weight": 2}, {"score": 3, "question": 0, "weight": 4}, {"score": 4, "question": 1, "weight": 4}, {"score": 2, "question": 2, "weight": 4}, {"score": 8, "question": 0, "weight": 2}],
result = data.reduce((r,o) => {
if(o.question == 0)
r.push([]);
r[r.length - 1].push(o);
return r;
},[]);
console.log(result);

let scores = [
{"score": 5, "question": 0, "weight": 2},
{"score": 4, "question": 1, "weight": 2},
{"score": 3, "question": 0, "weight": 4},
{"score": 4, "question": 1, "weight": 4},
{"score": 2, "question": 2, "weight": 4},
{"score": 8, "question": 0, "weight": 2}
]
let groupedScores = [], group = [];
scores.forEach((entry) => {
if(entry.question === 0) {
if (group.length) {
groupedScores.push(group);
}
group = [];
}
group.push(entry);
})
groupedScores.push(group)
console.log(groupedScores)

A bit simplified if splitting by just question: 0 :
data = [ { score: 5, question: 0, weight: 2 }, { score: 4, question: 1, weight: 2 },
{ score: 3, question: 0, weight: 4 }, { score: 4, question: 1, weight: 4 },
{ score: 2, question: 2, weight: 4 }, { score: 8, question: 0, weight: 2 } ]
result = data.reduce((r, v) => (v.question ? r[r.length-1].push(v) : r.push([v]), r), [])
console.log( result )

Related

Sum the values of a column

I have the array:
array = [
{
"id": 1,
"Price": 100,
"Item": {"id": 1, Name: "A"},
"Date": {"id": 1, Start: "202001"}
},
{
"id": 2,
"Price": 200,
"Item": {"id": 1, Name: "A"},
"Date": {"id": 2, Start: "202002"}
},
{
"id": 3,
"Price": 300,
"Item": {"id": 3, Name: "B"},
"Date": {"id": 2, Start: "202002"}
}
]
And I want to be able to sum the values for a given period, as shown in the table:
ITEM
202002
202003
TOTAL
A
100
200
300
B
300
300
TOTAL
100
500
600
Any suggestion? Thank!
have a look at this, it will start you down the right path
var aHolder = 0;
for(var i = 0; i<array.length; i++){
if(array[i].Date.Start === '202002') {
aHolder = aHolder + array[i].Price;
}
}
console.log(aHolder);

Javascript creates new arrays based on conditions

I have old and entity arrays:
var old = [
{
"id": 3,
"entity_type_id": 1,
"product_id": 4,
"name": "test1",
"acreage": 100,
"yield": 20,
"worth": 30
},
{
"id": 4,
"entity_type_id": 1,
"product_id": 4,
"name": "test2",
"acreage": 10,
"yield": 20,
"worth": 0
},
{
"id": 5,
"entity_type_id": 3,
"product_id": 5,
"name": "test3",
"acreage": 20,
"yield": 20,
"worth": 40
}
]
var entity = [
{"id": 1, "name": "a1"},
{"id": 2, "name": "a2"},
{"id": 3, "name": "a3"}
]
I hope to get the following data:
var newArr = [
{
"id": 3,
"entity_type_id": 1,
"product_id": 4,
"name": "test1",
"acreage": 110,
"yield": 40,
"worth": 30,
"entity_type_1": 2, // The total amount of entity_type_id (entity_type_id: 1)
"entity_type_2": 0,
"entity_type_3": 0
},
{
"id": 5,
"entity_type_id": 3,
"product_id": 5,
"name": "test3",
"acreage": 20,
"yield": 20,
"worth": 40,
"entity_type_1": 0,
"entity_type_2": 0,
"entity_type_3": 1 // The total amount of entity_type_id (entity_type_id: 3)
}
]
console.log(newArr)
I tried the following code and got some data. I'm not sure if there will be any exceptions or errors.
What's more, I don't know how to deal with the entity array data. Can someone help me solve this problem and get the result I expect?
Thank you very much !
function mergeArr(arr) {
const temp = []
arr.forEach((dataItem) => {
if (temp.length) {
let filterValue = temp.filter((items) => {
return items.product_id === dataItem.product_id
})
if (filterValue.length) {
temp.forEach((n) => {
if (n.product_id === filterValue[0].product_id) {
n.yield = dataItem.yield + filterValue[0].yield
n.acreage = dataItem.acreage + filterValue[0].acreage
n.worth = dataItem.worth + filterValue[0].worth
}
})
} else {
temp.push(dataItem)
}
} else {
temp.push(dataItem)
}
})
return temp
}
Youi could find the object and sum the wanted properties. For entity take another loop and map new entries and build a new object from it for spreading.
var old = [{ id: 3, entity_type_id: 1, product_id: 4, name: "test1", acreage: 100, yield: 20, worth: 30 }, { id: 4, entity_type_id: 1, product_id: 4, name: "test2", acreage: 10, yield: 20, worth: 0 }, { id: 5, entity_type_id: 3, product_id: 5, name: "test3", acreage: 20, yield: 20, worth: 40 }],
entity = [{ id: 1, name: "a1" }, { id: 2, name: "a2" }, { id: 3, name: "a3" }],
entityTypes = Object.fromEntries(entity.map(({ id }) => ['entity_type_' + id, 0])),
result = old.reduce((r, o) => {
let temp = r.find(q => q.product_id === o.product_id);
if (!temp) r.push(temp = { ... o, ...entityTypes });
else ['acreage', 'yield', 'worth'].forEach(k => temp[k] += o[k]);
temp['entity_type_' + o.entity_type_id]++;
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sorting array from Firebase fails

I'm trying to get an array of users sorted by the number of their likes. I am getting the user from a Firebase database, in case this changes things.
User example:
{
"likes": [
{
"createDate": {
"date": 22,
"day": 3,
"hours": 10,
"minutes": 33,
"month": 7,
"seconds": 25,
"time": 1534934005660,
"timezoneOffset": 0,
"year": 118
},
"creatorID": "1OA4U39rsPPXZblWG6nLHObB7gz1",
"firebaseKey": "-LKWBYQFbaO1Fs8_Rllc",
"workID": "-LK6-jxPZ0tCNW6c-GTI",
"id": "0"
},
{
"createDate": {
"date": 22,
"day": 3,
"hours": 13,
"minutes": 45,
"month": 7,
"seconds": 50,
"time": 1534938350990,
"timezoneOffset": -120,
"year": 118
},
"creatorID": "8Z7dd5L01FW0EbV0Wvu1KaXfmOx1",
"firebaseKey": "-LKWS7ZsUu2Khn0j7vLk",
"workID": "-LK5xZaui7IIcJcT22Rp",
"id": "1"
}
],
}
I was trying to use the sort method like this, but no luck.
var solversByLikes = solvers.sort((a, b) => a.likes.length - b.likes.length);
I am testing it by then console logging the solversByLikes array. This is the result:
0 LikesComponent.js:46
0 LikesComponent.js:46
0 LikesComponent.js:46
0 LikesComponent.js:46
2 LikesComponent.js:46
2 LikesComponent.js:46
But if I switch the a, and b, so that the sorting should be reversed, nothing changes.
var solversByLikes = solvers.sort((a, b) => b.likes.length - a.likes.length);
I tried replicating the issue like this:
allUsers = [{likes: [1, 2, 3, 4, 5, 6, 7, 8]}, {likes: [1, 2,]}, {likes: [1, 2, 3, 4, 5, 6,]}, {likes: [1, 2, 3, 4, 5,]}, {likes: [1, 2, 3, 4,]}, {likes: [1, 2, 3]}]
solversByLikes = allUsers.sort((a, b) => b.likes.length - a.likes.length);
solversByLikes.forEach(user => console.log(user.likes.length));
But this works as intended...
Any idea how to make it sort?
I'm not getting any error or anything.

JavaScript array.filter() and iterator

got a array of objects and need to filter this by 2 criterias. One of those criterias is an index counting up.
let data =
[{"hour": 1, "dayIndex": 0, "value": "something"},
{"hour": 1, "dayIndex": 1, "value": "something"},
{"hour": 1, "dayIndex": 3, "value": "something"},
{"hour": 2, "dayIndex": 0, "value": "something"},
{"hour": 2, "dayIndex": 1, "value": "something"},
// and so on
]
I need an array of objects filtered by "hour" and ascending "dayIndex" and it is important that for missing dayIndexes an empty object is created. So for hour=1 I would need this:
let hourOneArray =
[
{"hour" : 1, "dayIndex": 0, "value": "something"},
{"hour" : 1, "dayIndex": 1, "value": "something"},
{}, //empty because dayIndex 2 is missing
{"hour" : 1, "dayIndex": 3, "value": "something"},
{}, //empty because dayIndex 4 is missing
]
My approach was:
for(let i = 0; i < 4; ++i){
hourOneArray = data.filter((arg) => {
return ((arg.hour === 1) && (arg.dayIndex === i));
})
}
Thanks in advance
Here's a quick and clean solution to filter all of them by hour, filling in blank days. Make use of map and reduce :D
let data =
[{"hour": 1, "dayIndex": 0, "value": "something"},
{"hour": 1, "dayIndex": 1, "value": "something"},
{"hour": 1, "dayIndex": 3, "value": "something"},
{"hour": 2, "dayIndex": 0, "value": "something"},
{"hour": 2, "dayIndex": 1, "value": "something"},
// and so on
]
let defaultArr = [];
data.forEach(val => defaultArr.push({}));
let output = data.reduce((hash, val) => {
let hour = val.hour;
let dayIndex = val.dayIndex;
if(!hash[hour]) hash[hour] = defaultArr.map(val => val);
hash[hour][dayIndex] = val;
return hash;
}, {})
console.log(output);
You can try following
let data = [{"hour": 1, "dayIndex": 0, "value": "something"},{"hour": 1, "dayIndex": 1, "value": "something"},{"hour": 2, "dayIndex": 0, "value": "something"},{"hour": 2, "dayIndex": 1, "value": "something"},{"hour": 1, "dayIndex": 3, "value": "something"}];
// Sort the array by hour and dayIndex
data.sort((a,b) => a.hour - b.hour || a.dayIndex - b.dayIndex);
function getHourData(hour) {
// Get the hour data
var hourData = data.filter((a) => a.hour === hour);
// Now, iterate till the maximum dayIndex of the filtered array
for (let i = 0; i < hourData[hourData.length -1].dayIndex; i++) {
// If the index is different from dayIndex, count it as missing and add it to the array
if(i !== hourData[i].dayIndex) hourData.splice(i,0, {});
}
// return result
return hourData;
}
console.log(getHourData(1));
let data =
[{"hour": 1, "dayIndex": 0, "value": "something"},
{"hour": 1, "dayIndex": 1, "value": "something"},
{"hour": 1, "dayIndex": 3, "value": "something"},
{"hour": 2, "dayIndex": 0, "value": "something"},
{"hour": 2, "dayIndex": 1, "value": "something"}]
data= data.sort((a,b)=>a.dayIndex-b.dayIndex);
data = data.map(val=>val.hour == 1?val:{});
console.log(data);
You can reduce into an object indexed by dayIndex, then add the objects for each missing day, no sorting needed (O(n)):
const input =
[{"hour": 1, "dayIndex": 0, "value": "something"},
{"hour": 1, "dayIndex": 1, "value": "something"},
{"hour": 1, "dayIndex": 3, "value": "something"},
{"hour": 2, "dayIndex": 0, "value": "something"},
{"hour": 2, "dayIndex": 1, "value": "something"},
];
const [groupedByDay, haveDays] = input
.reduce(([groupedByDay, haveDays], item) => {
const { hour, dayIndex } = item;
if (hour === 1 && !groupedByDay[dayIndex]) {
groupedByDay[dayIndex] = item;
haveDays.push(dayIndex);
}
return [groupedByDay, haveDays];
}, [{}, []]);
const length = Math.max(...haveDays) + 1;
const hourOneArray = Array.from({ length }, (_, i) => (
groupedByDay[i] ? groupedByDay[i] : {}
));
console.log(hourOneArray);

Reverse level of treeview javascript

Please help me out to create treeview by javascript array. The scenario is I want to create treeview with reverse level.
For Example:
I have an array in below format:
var arr = [
{'id':1 ,'parentid' : 0},
{'id':2 ,'parentid' : 1},
{'id':3 ,'parentid' : 1},
{'id':4 ,'parentid' : 2},
{'id':5 ,'parentid' : 0},
{'id':6 ,'parentid' : 0},
{'id':7 ,'parentid' : 4}
];
and I am trying to create treeview in below order:
Expected output:
[
{
"id": 1,
"parentid": 0,
level:4,
"children": [
{
"id": 2,
"parentid": 1,
level:3,
"children": [
{
"id": 4,
"parentid": 2,
level:2,
"children": [
{
"id": 7,
"parentid": 4,
level:1
}
]
}
]
},
{
"id": 3,
"parentid": 1,
level:3
}
]
},
{
"id": 5,
"parentid": 0
level:4
},
{
"id": 6,
"parentid": 0,
level:4
}
]
Basically the task is solved in three steps
build tree
get the maximal level
apply the level
var arr = [{ 'id': 1, 'parentid': 0 }, { 'id': 2, 'parentid': 1 }, { 'id': 3, 'parentid': 1 }, { 'id': 4, 'parentid': 2 }, { 'id': 5, 'parentid': 0 }, { 'id': 6, 'parentid': 0 }, { 'id': 7, 'parentid': 4 }],
tree = function (array) {
function iterGet(o) {
if (Array.isArray(o.children)) {
maxLevel++;
o.children.forEach(iterGet);
}
}
function iterSet(level) {
return function (o) {
o.level = level;
Array.isArray(o.children) && o.children.forEach(iterSet(level - 1));
}
}
var o = { id: 0 },
maxLevel = 1;
array.forEach(function (a) {
o[a.id] = o[a.id] || { id: a.id };
a.children = o[a.id].children;
o[a.parentid] = o[a.parentid] || { id: a.parentid };
o[a.parentid].children = o[a.parentid].children || [];
o[a.parentid].children.push(o[a.id]);
});
iterGet(o[0]);
iterSet(maxLevel)(o[0]);
return o[0].children;
}(arr);
document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');

Categories

Resources