Related
I want to move items to the top of my array when the values are found within another array.
const data = [
{ value: 'BMW', count: 1 },
{ value: 'AUDI', count: 1 },
{ value: 'VAUXHALL', count: 1 },
{ value: 'FIAT', count: 1 },
{ value: 'HONDA', count: 1 },
{ value: 'LANDROVER', count: 1 },
];
const selected = [ 'AUDI', 'HONDA' ];
So basically the above will turn into:
const data = [
{ value: 'AUDI', count: 1 },
{ value: 'HONDA', count: 1 },
{ value: 'BMW', count: 1 },
{ value: 'VAUXHALL', count: 1 },
{ value: 'FIAT', count: 1 },
{ value: 'LANDROVER', count: 1 },
];
This is what I have at the moment, however it doesn't work as expected and it's not nice at all:
let prepend = [];
selected.forEach(selected => {
for (let i = 0; i < data.length; i++) {
if (data[i] && data[i].value === selected) {
prepend.push(data[i]);
delete data[i];
break;
}
}
})
data.unshift(...prepend);
data = data.filter(Boolean);
I want to do something cleaner like this:
return [...data].sort((a, b) => {
});
You can take advantage of boolean arithmetic operations with Array#includes and Array#sort.
const data = [
{ value: 'BMW', count: 1 },
{ value: 'AUDI', count: 1 },
{ value: 'VAUXHALL', count: 1 },
{ value: 'FIAT', count: 1 },
{ value: 'HONDA', count: 1 },
{ value: 'LANDROVER', count: 1 },
];
const selected = [ 'AUDI', 'HONDA' ];
data.sort((a, b) => selected.includes(b.value) - selected.includes(a.value))
console.log(data);
I have an array as below.
const list = [
{
date: "2020-01-01",
number: 3,
count: 2
},
{
date: "2020-01-01",
number: 3,
count: 2
},
{
date: "2020-01-01",
number: 3,
count: 2
},
{
date: "2020-01-02",
number: 4,
count: 1
},
{
date: "2020-01-02",
number: 4,
count: 1
}
]
And I want to sum number and count depends on same date. After that it should be merged in same date. Therefore I want to get the result as below.
const list = [{
totalNumber: 9,
totalCount: 6,
detail:[{
date: "2020-01-01",
number: 3,
count: 2
},
{
date: "2020-01-01",
number: 3,
count: 2
},
{
date: "2020-01-01",
number: 3,
count: 2
}]
},
{
totalNumber: 8,
totalCount: 2,
detail:[
{
date: "2020-01-02",
number: 4,
count: 1
},
{
date: "2020-01-02",
number: 4,
count: 1
}]
}
]
I know stackoverflow is not code writing site. But I made this from some data. But this is my last stage for completing my object. And I don't know how I can group like that. I'' appreciate if you help me to resolve this problem. Thank you so much for reading it.
To me, optimal approach is building Map (having necessary property as a key) with Array.prototype.reduce(), then extracting array of values (aggregated records) with Map.prototype.values():
const src = [{date:"2020-01-01",number:3,count:2},{date:"2020-01-01",number:3,count:2},{date:"2020-01-01",number:3,count:2},{date:"2020-01-02",number:4,count:1},{date:"2020-01-02",number:4,count:1}],
groupped = [...src
.reduce((acc, {date, number, count}) => {
const group = acc.get(date)
if(group){
group.totalNumber += number
group.totalCount += count
group.detail.push({date, number, count})
} else {
acc.set(
date,
{
date,
totalNumber: number,
totalCount: count,
detail: [{
date,
number,
count
}]
}
)
}
return acc
}, new Map)
.values()
]
console.log(groupped)
.as-console-wrapper{min-height:100%;}
I have a requirement to group an array of objects based on time interval. The input looks like:
[
{
_id: {
hour: 0,
interval: '0'
},
time: '0:0',
count: 10
},
{
_id: {
hour: 0,
interval: '15'
},
time: '0:15',
count: 5
},
{
_id: {
hour: 0,
interval: '30'
},
time: '0:30',
count: 1
},
{
_id: {
hour: 0,
interval: '45'
},
time: '0:45',
count: 2
},
{
_id: {
hour: 1,
interval: '0'
},
time: '1:0',
count: 4
},
{
_id: {
hour: 1,
interval: '15'
},
time: '1:15',
count: 3
},
{
_id: {
hour: 1,
interval: '30'
},
time: '1:30',
count: 5
},
{
_id: {
hour: 1,
interval: '45'
},
time: '1:45',
count: 1
}
]
My desired output:
[
{
"time": "0",
"0": 10,
"15": 5
"30": 1,
"45": 2
},
{
"time": "1",
"0": 4,
"15": 3
"30": 5,
"45": 1
}
]
I tried to use the following code to group the objects, which works to an extent, but I'm stuck on what to do next:
const a = [ { _id: { hour: 0, interval: '0' }, time: '0:0', count: 10 }, { _id: { hour: 0, interval: '15' }, time: '0:15', count: 5 }, { _id: { hour: 0, interval: '30' }, time: '0:30', count: 1 }, { _id: { hour: 0, interval: '45' }, time: '0:45', count: 2 }, { _id: { hour: 1, interval: '0' }, time: '1:0', count: 4 }, { _id: { hour: 1, interval: '15' }, time: '1:15', count: 3 }, { _id: { hour: 1, interval: '30' }, time: '1:30', count: 5 }, { _id: { hour: 1, interval: '45' }, time: '1:45', count: 1 }]
var group = a.reduce((r, a) => {
console.log("a", a);
console.log('r', r);
r[a._id.hour] = [...r[a._id.hour] || [], a];
return r;
}, {});
console.log("group", group);
Check if the object with that hour exists in the accumulator object first - if it doesn't, create one, then assign count to that object's [interval] property, and get the Object.values at the end to turn it back into an array:
const input=[{_id:{hour:0,interval:"0"},time:"0:0",count:10},{_id:{hour:0,interval:"15"},time:"0:15",count:5},{_id:{hour:0,interval:"30"},time:"0:30",count:1},{_id:{hour:0,interval:"45"},time:"0:45",count:2},{_id:{hour:1,interval:"0"},time:"1:0",count:4},{_id:{hour:1,interval:"15"},time:"1:15",count:3},{_id:{hour:1,interval:"30"},time:"1:30",count:5},{_id:{hour:1,interval:"45"},time:"1:45",count:1}];
const groupedObj = {};
for (const { _id: { hour, interval }, count } of input) {
if (!groupedObj[hour]) {
groupedObj[hour] = { time: hour };
}
groupedObj[hour][interval] = count;
}
const output = Object.values(groupedObj);
console.log(output);
Reduce the array, and create an object for each _id.time. Assign the current [interval] = count to the object. Get the entries, and use Array.from() to convert the entries to an array of the required form:
const arr = [{"_id":{"hour":0,"interval":"0"},"time":"0:0","count":10},{"_id":{"hour":0,"interval":"15"},"time":"0:15","count":5},{"_id":{"hour":0,"interval":"30"},"time":"0:30","count":1},{"_id":{"hour":0,"interval":"45"},"time":"0:45","count":2},{"_id":{"hour":1,"interval":"0"},"time":"1:0","count":4},{"_id":{"hour":1,"interval":"15"},"time":"1:15","count":3},{"_id":{"hour":1,"interval":"30"},"time":"1:30","count":5},{"_id":{"hour":1,"interval":"45"},"time":"1:45","count":1}];
// convert the entries to an array
const result = Array.from(Object.entries(
arr.reduce((r, o) => {
const { hour, interval } = o._id; // get the hour and interval
if(!r[hour]) r[hour] = {}; // create a the hour object
r[hour][interval] = o.count; // add the interval and count
return r;
}, {})
), ([time, values]) => ({ time, ...values })); // generate the result objects
console.log(result)
You can group object by reduce method. So at first you need to group by hour and then just add interval properties from each iteration of reduce method to the hour property:
const result = arr.reduce((a, c) => {
a[c._id.hour] = a[c._id.hour] || {};
a[c._id.hour].time = c._id.hour;
a[c._id.hour][c._id.interval] = c.count;
return a;
}, {})
console.log(result);
An example:
let arr = [
{
_id: {
hour: 0,
interval: '0'
},
time: '0:0',
count: 10
},
{
_id: {
hour: 0,
interval: '15'
},
time: '0:15',
count: 5
},
{
_id: {
hour: 0,
interval: '30'
},
time: '0:30',
count: 1
},
{
_id: {
hour: 0,
interval: '45'
},
time: '0:45',
count: 2
},
{
_id: {
hour: 1,
interval: '0'
},
time: '1:0',
count: 4
},
{
_id: {
hour: 1,
interval: '15'
},
time: '1:15',
count: 3
},
{
_id: {
hour: 1,
interval: '30'
},
time: '1:30',
count: 5
},
{
_id: {
hour: 1,
interval: '45'
},
time: '1:45',
count: 1
}
]
const result = arr.reduce((a, c) => {
a[c._id.hour] = a[c._id.hour] || {};
a[c._id.hour].time = c._id.hour;
a[c._id.hour][c._id.interval] = c.count;
return a;
}, {})
console.log(result);
I have the following array:
var objArray = [
{ num: 1, date: '1/12/2017' },
{ num: 3, date: '1/12/2017' },
{ num: 7, date: '1/12/2017' },
{ num: 1, date: '1/13/2018' },
{ num: 3, date: '1/16/2018' },
{ num: 4, date: '1/16/2018' }
];
I want to combine those with same dates so that the output array looks like this:
var outputArr = [
{ num: 11, date: '1/12/2017' },
{ num: 1, date: '1/13/2018' },
{ num: 7, date: '1/16/2018' }
];
I'm adding all num with similar dates and creating a single new object.
I have a very large dataset of objects like this so I'm trying to reduce the amount of processing time for this.
I've got the arrays sorted by date so that it mirrors objArray.
For loops seems cumbersome since I'm taking the first date in the array and checking every other element in the array a la the following pseudo-code:
var newArr = [];
for(i = 0; i < objArray.length; i++) {
for(j = 0; j < objArray.length; j++) {
var tempArr = [];
// check every date manually
// add similar to new array
tempArr.push({ similar items });
}
newArr.push(tempArr):
}
// Do another couple loops to combine those like arrays into another array
There has to be a more elegant way to perform this than running multiple for loops.
Any suggestions would be appreciated.
Simply use Array.reduce() to create a map and group values by date, Object.values() on the map will give you the desired output value:
let arr = [ { num: 1, date: '1/12/2017' }, { num: 3, date: '1/12/2017' }, { num: 7, date: '1/12/2017' }, { num: 1, date: '1/13/2018' }, { num: 3, date: '1/16/2018' }, { num: 4, date: '1/16/2018' } ];
let result = Object.values(arr.reduce((a, {num, date})=>{
if(!a[date])
a[date] = Object.assign({},{num, date});
else
a[date].num += num;
return a;
},{}));
console.log(result);
Using lodash,
// Aggregate num from unique dates
var g = _.groupBy(objArray,'date')
Object.keys(g).map(k=>({num:g[k].reduce((a,c)=>c.num+a,0),date:k}))
var objArray = [
{ num: 1, date: '1/12/2017' },
{ num: 3, date: '1/12/2017' },
{ num: 7, date: '1/12/2017' },
{ num: 1, date: '1/13/2018' },
{ num: 3, date: '1/16/2018' },
{ num: 4, date: '1/16/2018' }
];
let outputArr = Array.from(objArray.reduce((acc, obj)=>{
acc.set(obj.date, (acc.get([obj.date]) || 0) + obj.num);
return acc;
}, new Map()))
.map(kv=>({num: kv[1], date: kv[0]}))
console.log(outputArr);
gives:
[ { num: 11, date: '1/12/2017' },
{ num: 1, date: '1/13/2018' },
{ num: 7, date: '1/16/2018' } ]
You could also remove the if statements and use a Set if you wanted to be even more declarative.
var objArray = [
{ num: 1, date: '1/12/2017' },
{ num: 3, date: '1/12/2017' },
{ num: 7, date: '1/12/2017' },
{ num: 1, date: '1/13/2018' },
{ num: 3, date: '1/16/2018' },
{ num: 4, date: '1/16/2018' }
];
var mSet = new Set(objArray.map(d => d.date));
return Array.from(mSet).map(d => {
return
{
date: d,
sum: (objArray
.filter(o => o.date === d)
.map(n => n.num)
.reduce((a, c) => a + c, 0))
}
);
This returns:
[{ date: 1/12/2017, sum: 11},
{ date: 1/13/2018, sum: 1 },
{ date: 1/16/2018, sum: 7 }]
Here's another way. It's more verbose, but if you're just starting out it might be easier to understand as opposed to using array methods like reduce().
objArray = [
{ num: 1, date: '1/12/2017' },
{ num: 3, date: '1/12/2017' },
{ num: 7, date: '1/12/2017' },
{ num: 1, date: '1/13/2018' },
{ num: 3, date: '1/16/2018' },
{ num: 4, date: '1/16/2018' }
]
function combineObj(data) {
let validator= new Set();
let combinedArr = [];
let numCount = 0;
// Create a list of unique properties to match against:
data.forEach((e) => validator.add(e.date));
// For each value in the validator, create a new object in a new array
// and add the unique values from the validator to the respective property:
validator.forEach((e) => {
combinedArr.push({
num: 0,
date: e
});
})
// Lastly, for each object in the combinedArr, use a counter to sum up the total values of each property
// as you loop through your data:
combinedArr.forEach((e) => {
numCount = 0;
data.forEach((ee) => {
if (e.date === ee.date) {
numCount += ee.num;
e.num = numCount;
}
})
})
return combinedArr;
}
Returns:
[
{ num: 11, date: '1/12/2017' },
{ num: 1, date: '1/13/2018' },
{ num: 7, date: '1/16/2018' }
]
I've got data I need to sort through, filter, and store in a specific way. I'll explain by showing. Here is the data:
var pieData, cakeData, icecreamData;
var desserts = [
{
pies: [
{
name: "blueberry",
count: 3
},
{
name: "pumpkin",
count: 6
},
{
name: "apple",
count: 9
}
],
cakes: [
{
name: "chocolate",
count: 3
},
{
name: "foam",
count: 6
},
{
name: "wedding",
count: 9
}
],
icecream: [
{
name: "chocolate",
count: 3
},
{
name: "strawberry",
count: 6
},
{
name: "mint-chip",
count: 9
}
],
date: "2016-01-06T00:00:00"
},
{
pies: [
{
name: "blueberry",
count: 2
},
{
name: "pumpkin",
count: 4
},
{
name: "apple",
count: 6
}
],
cakes: [
{
name: "chocolate",
count: 2
},
{
name: "foam",
count: 4
},
{
name: "wedding",
count: 6
}
],
icecream: [
{
name: "chocolate",
count: 2
},
{
name: "strawberry",
count: 4
},
{
name: "mint-chip",
count: 6
}
],
date: "2016-01-07T00:00:00"
},
{
pies: [
{
name: "blueberry",
count: 4
},
{
name: "pumpkin",
count: 8
},
{
name: "apple",
count: 12
}
],
cakes: [
{
name: "chocolate",
count: 4
},
{
name: "foam",
count: 8
},
{
name: "wedding",
count: 12
}
],
icecream: [
{
name: "chocolate",
count: 4
},
{
name: "strawberry",
count: 8
},
{
name: "mint-chip",
count: 12
}
],
date: "2016-01-08T00:00:00"
}
];
So I've got my data. The data is basically what types of pies, cakes, and icereams there are which can vary in number, name, and count. Each object in desserts is a day, with the date as the last property. I'll go straight to what I want to get out of it and then explain further after that. Here is what I need to get out of it:
pieData = [
{
name: "blueberry",
dates: ["2016-01-06T00:00:00", "2016-01-07T00:00:00", "2016-01-08T00:00:00"],
counts: [3, 2, 4]
},
{
name: "pumpkin",
dates: ["2016-01-06T00:00:00", "2016-01-07T00:00:00", "2016-01-08T00:00:00"],
counts: [6, 4, 8]
},
{
name: "apple",
dates: ["2016-01-06T00:00:00", "2016-01-07T00:00:00", "2016-01-08T00:00:00"],
counts: [9, 6, 12]
}
];
cakeData = [
{
name: "chocolate",
dates: ["2016-01-06T00:00:00", "2016-01-07T00:00:00", "2016-01-08T00:00:00"],
counts: [3, 2, 4]
},
{
name: "foam",
dates: ["2016-01-06T00:00:00", "2016-01-07T00:00:00", "2016-01-08T00:00:00"],
counts: [6, 4, 8]
},
{
name: "wedding",
dates: ["2016-01-06T00:00:00", "2016-01-07T00:00:00", "2016-01-08T00:00:00"],
counts: [9, 6, 12]
}
];
icecreamData = [
{
name: "chocolate",
dates: ["2016-01-06T00:00:00", "2016-01-07T00:00:00", "2016-01-08T00:00:00"],
counts: [3, 2, 4]
},
{
name: "strawberry",
dates: ["2016-01-06T00:00:00", "2016-01-07T00:00:00", "2016-01-08T00:00:00"],
counts: [6, 4, 8]
},
{
name: "mint-chip",
dates: ["2016-01-06T00:00:00", "2016-01-07T00:00:00", "2016-01-08T00:00:00"],
counts: [9, 6, 12]
}
];
So I need to pass the desserts variable to a function and have it set the pieData, cakeData, and icecreamData variables, declared at the top of the original data, to the array of objects I've shown in the second bit of code.
A Few Things to Note:
In the output data, the values correspond to the days they were originally assigned in the original data. For example, pieData[0].dates[0] corresponds to pieData[0].counts[0] as it appears in the original data.
There could be infinite types of each dessert or none. Meaning there could be 10 different objects in the "pie" array in the original data or none. But there will always be pies, cakes, and icecream arrays, whether they are empty or have a thousand objects in them.
I don't know what types of each dessert will come through. It could be anything. So the pie could be named "pumpkin" or it could be named "battery acid".
My only solution I could think of was to do multiple loops and nested loops and just overall too much code. I know there has to be some efficient wizardry to get this done right.
I understand the drive to want "minified" code, but I think it's best to keep things readable. Despite your reservations, I think a few nested loops make sense in this case.
Consider the following way of getting the desired result:
var pieData, cakeData, icecreamData;
var desserts = [{pies:[{name:"blueberry",count:3},{name:"pumpkin",count:6},{name:"apple",count:9}],cakes:[{name:"chocolate",count:3},{name:"foam",count:6},{name:"wedding",count:9}],icecream:[{name:"chocolate",count:3},{name:"strawberry",count:6},{name:"mint-chip",count:9}],date:"2016-01-06T00:00:00"},{pies:[{name:"blueberry",count:2},{name:"pumpkin",count:4},{name:"apple",count:6}],cakes:[{name:"chocolate",count:2},{name:"foam",count:4},{name:"wedding",count:6}],icecream:[{name:"chocolate",count:2},{name:"strawberry",count:4},{name:"mint-chip",count:6}],date:"2016-01-07T00:00:00"},{pies:[{name:"blueberry",count:4},{name:"pumpkin",count:8},{name:"apple",count:12}],cakes:[{name:"chocolate",count:4},{name:"foam",count:8},{name:"wedding",count:12}],icecream:[{name:"chocolate",count:4},{name:"strawberry",count:8},{name:"mint-chip",count:12}],date:"2016-01-08T00:00:00"}];
var dessertData= {};
for (var dessertGroup of desserts) {
for (var item in dessertGroup) {
// the timestamp is not a dessert, so skip it
if (item === 'date') { continue; }
if (!dessertData[item]) {
// this is a new kind of dessert, add it
dessertData[item] = [];
}
for (var flavour of dessertGroup[item]) {
// get the index of the flavour
var index = dessertData[item].map(function(e) { return e.name; }).indexOf(flavour.name);
if (index < 0) {
// this is a new flavour of dessert, add it to the dessert type
dessertData[item].push({
name: flavour.name,
dates: [],
counts: []
});
index = dessertData[item].length - 1;
}
// append the relevant data to the flavour properties
dessertData[item][index].dates.push(dessertGroup.date);
dessertData[item][index].counts.push(flavour.count);
}
}
}
// finally, we want 'cakes' in 'cakeData'
// 'pies' in 'pieData'
// and 'icecream in 'icecreamData'
cakeData = dessertData.cakes;
pieData = dessertData.pies;
icecreamData = dessertData.icecream;
console.log("cakeData=", cakeData);
console.log("pieData=", pieData);
console.log("icecreamData=", icecreamData);
This is easy to read and modify. Also, it allows for any type of dessert! Why limit yourself to pies, cake, and icecream.
You'll notice that I'm dynamically creating and accessing the properties of dessertData by doing stuff like dessertData[propertyName].
Maybe you knew that was possible, but I used javascript for a long time before learning that the [] syntax wasn't just for numerical indices. Good luck!
This converts it into the format you want
https://jsfiddle.net/sdhjL7dv/
var pieData = [], cakeData = [], icecreamData = [];
var desserts = [
{
pies: [
{
name: "blueberry",
count: 3
},
{
name: "pumpkin",
count: 6
},
{
name: "apple",
count: 9
}
],
cakes: [
{
name: "chocolate",
count: 3
},
{
name: "foam",
count: 6
},
{
name: "wedding",
count: 9
}
],
icecream: [
{
name: "chocolate",
count: 3
},
{
name: "strawberry",
count: 6
},
{
name: "mint-chip",
count: 9
}
],
date: "2016-01-06T00:00:00"
},
{
pies: [
{
name: "blueberry",
count: 2
},
{
name: "pumpkin",
count: 4
},
{
name: "apple",
count: 6
}
],
cakes: [
{
name: "chocolate",
count: 2
},
{
name: "foam",
count: 4
},
{
name: "wedding",
count: 6
}
],
icecream: [
{
name: "chocolate",
count: 2
},
{
name: "strawberry",
count: 4
},
{
name: "mint-chip",
count: 6
}
],
date: "2016-01-07T00:00:00"
},
{
pies: [
{
name: "blueberry",
count: 4
},
{
name: "pumpkin",
count: 8
},
{
name: "apple",
count: 12
}
],
cakes: [
{
name: "chocolate",
count: 4
},
{
name: "foam",
count: 8
},
{
name: "wedding",
count: 12
}
],
icecream: [
{
name: "chocolate",
count: 4
},
{
name: "strawberry",
count: 8
},
{
name: "mint-chip",
count: 12
}
],
date: "2016-01-08T00:00:00"
}
];
for(var i = 0; i < desserts.length; i++) {
var d = desserts[i].date;
desserts[i].pies.length && save(pieData, desserts[i].pies, d);
desserts[i].cakes.length && save(cakeData, desserts[i].cakes, d);
desserts[i].icecream.length && save(icecreamData, desserts[i].icecream, d);
}
function save(destination, items, d) {
for(var i = 0; i < items.length; i++) {
var name = items[i].name;
var count = items[i].count;
if(destination[name] === undefined) { destination[name] = {name:'',dates:[],counts:[]}; }
destination[name].name = name;
destination[name].dates.push(d);
destination[name].counts.push(count);
}
}
console.log(pieData);
console.log(cakeData);
console.log(icecreamData);