i'm trying to get some data together based on some data.
So for example as seen below the items array displays the total amount of times a number is between the range in the data, so for example 4500 - 5000 has got 4 numbers between that range.
However adding these up doesn't give an accurate representation of the amount of items there is. If this makes sense? As in the result the count for 7000 is 13, however this should be 8.
const data = [ 2200, 3900, 4500, 4500, 4800, 5000, 6000, 6000 ]
const items = [
{ value: { from: 2000, to: 2500 }, count: null },
{ value: { from: 2500, to: 3000 }, count: null },
{ value: { from: 3000, to: 3500 }, count: null },
{ value: { from: 3500, to: 4000 }, count: null },
{ value: { from: 4000, to: 4500 }, count: null },
{ value: { from: 4500, to: 5000 }, count: null },
{ value: { from: 5000, to: 5500 }, count: null },
{ value: { from: 5500, to: 6000 }, count: null },
{ value: { from: 6000, to: 6500 }, count: null },
{ value: { from: 6500, to: 7000 }, count: null },
].map(item => {
item.count = data.filter(x => x <= item.value.to && x >= item.value.from).length;
return item;
});
let counter = 0;
result = items.map(i => {
counter += i.count;
return { value: i.value.to, label: i.value.to, count: counter }
}).filter(Boolean);
console.log({items, result});
What I SHOULD have is the following, as this data is for an UPTO dropdown.
[
{ value: { from: 2000, to: 2500 }, count: 1 },
{ value: { from: 2500, to: 3000 }, count: 1 },
{ value: { from: 3000, to: 3500 }, count: 1 },
{ value: { from: 3500, to: 4000 }, count: 2 },
{ value: { from: 4000, to: 4500 }, count: 4 },
{ value: { from: 4500, to: 5000 }, count: 6 },
{ value: { from: 5000, to: 5500 }, count: 6 },
{ value: { from: 5500, to: 6000 }, count: 8 },
{ value: { from: 6000, to: 6500 }, count: 8 },
{ value: { from: 6500, to: 7000 }, count: 8 },
]
You should not consider both from and to inside the boundary. This will result in having common elements in individual groups.
For example: From 4000 to 4500 means numbers greater than 4000 and less than or equal to 4500.
Here in the above example, the lover boundary donot overlaps, so that the individual groups donot have common elements.
const data = [2200, 3900, 4500, 4500, 4800, 5000, 6000, 6000]
const items = [
{ value: { from: 2000, to: 2500 }, count: null },
{ value: { from: 2500, to: 3000 }, count: null },
{ value: { from: 3000, to: 3500 }, count: null },
{ value: { from: 3500, to: 4000 }, count: null },
{ value: { from: 4000, to: 4500 }, count: null },
{ value: { from: 4500, to: 5000 }, count: null },
{ value: { from: 5000, to: 5500 }, count: null },
{ value: { from: 5500, to: 6000 }, count: null },
{ value: { from: 6000, to: 6500 }, count: null },
{ value: { from: 6500, to: 7000 }, count: null },
].map(item => {
item.count = data.filter(x => x <= item.value.to && x > item.value.from).length;
return item;
});
let counter = 0;
result = items.map(i => {
counter += i.count;
return { value: i.value.to, label: i.value.to, count: counter }
}).filter(Boolean);
console.log({ items, result });
You could take a single loop and map a new object with count.
const
data = [2200, 3900, 4500, 4500, 4800, 5000, 6000, 6000],
values = [{ value: { from: 2000, to: 2500 }, count: null }, { value: { from: 2500, to: 3000 }, count: null }, { value: { from: 3000, to: 3500 }, count: null }, { value: { from: 3500, to: 4000 }, count: null }, { value: { from: 4000, to: 4500 }, count: null }, { value: { from: 4500, to: 5000 }, count: null }, { value: { from: 5000, to: 5500 }, count: null }, { value: { from: 5500, to: 6000 }, count: null }, { value: { from: 6000, to: 6500 }, count: null }, { value: { from: 6500, to: 7000 }, count: null }],
items = values.map(item => ({
...item,
count: data.reduce((s, x) => s + (x <= item.value.to), 0)
}));
console.log(items);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
i want group by value and my problem is screen_size and screen_resulation is changeable
is there is something like wildcard in nested document in mongodb ?
i have tried this but its not working
[
{
filters: {
screen_size: {
name: "حجم الشاشة",
value: "50",
},
screen_resulation: {
name: "دقة الشاشة",
value: "4k",
},
},
},
{
filters: {
screen_resulation: {
name: "دقة الشاشة",
value: "UHD",
},
screen_size: {
name: "حجم الشاشة",
value: "55",
},
},
},
{
filters: {
screen_resulation: {
name: "دقة الشاشة",
value: "4k",
},
screen_size: {
name: "حجم الشاشة",
value: "55",
},
},
},
];
{
$group : {
_id: "$filters.*.value", counter: { $sum: 1 }
}
}
You can get the desired result with the below approach as well:
[{$project: {
_id: '$_id',
filters: { $objectToArray: '$filters' }
}}, {$unwind: {
path: '$filters'
}}, {$group: {
_id: '$filters.v.value',
count: {$sum: 1}
}}]
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);
This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 4 years ago.
I am working for the first time on a project with JSON but I need to get al timestamps form the JSON file to put it in a array in a chart that al the timestamps are displaying on the chart.
JSON file look like this:
[
{
timestamp: "1541404800",
data: {
OK: {
count: "8",
percentage: "100"
},
NOK: {
count: 0,
percentage: 0
}
}
},
{
timestamp: "1541408400",
data: {
OK: {
count: "1",
percentage: "100"
},
NOK: {
count: 0,
percentage: 0
}
}
}
]
what you are looking for is the function map. See documentation for more details.
for example:
var data = [
{
timestamp: '1541404800',
data: {
OK: {
count: '8',
percentage: '100'
},
NOK: {
count: 0,
percentage: 0
}
}
},
{
timestamp: '1541408400',
data: {
OK: {
count: '1',
percentage: '100'
},
NOK: {
count: 0,
percentage: 0
}
}
}
];
var timestamps = data.map(function(d) { return d.timestamp }));
Just use for to iterate over the array to get the data
var json = [
{
timestamp: '1541404800',
data: {
OK: {
count: '8',
percentage: '100'
},
NOK: {
count: 0,
percentage: 0
}
}
},
{
timestamp: '1541408400',
data: {
OK: {
count: '1',
percentage: '100'
},
NOK: {
count: 0,
percentage: 0
}
}
}
];
var newArr = [];
for (var i = 0; i < json.length; i++) {
newArr.push(json[i].timestamp);
}
console.log(newArr); // ['1541404800','1541408400']
So i'm getting this pretty complex array from an API with lots of nested arrays with objects etc. It looks like this:
public data: any[] = [
{
language: 'Dutch',
sources: [
{
source: 'De Redactie',
channels: [
{ channel: 'binnenland', value: false },
{ channel: 'buitenland', value: false },
{ channel: 'sport', value: false },
{ channel: 'cultuur en media', value: false },
{ channel: 'politiek', value: false },
{ channel: 'financien', value: false }
]
},
{
source: 'Tweakers',
channels: [
{ channel: 'hardware', value: false },
{ channel: 'software', value: false },
{ channel: 'tech', value: false },
{ channel: 'smartphones', value: false },
{ channel: 'audio', value: false },
{ channel: 'video', value: false }
]
}
]
},
{
language: 'English',
sources: [
{
source: 'BBC',
channels: [
{ channel: 'news', value: false },
{ channel: 'sport', value: false },
{ channel: 'weather', value: false },
{ channel: 'travel', value: false },
{ channel: 'politics', value: false }
]
},
{
source: 'Fox News',
channels: [
{ channel: 'u.s.', value: false },
{ channel: 'world', value: false },
{ channel: 'opinion', value: false },
{ channel: 'politics', value: false },
{ channel: 'entertainment', value: false },
{ channel: 'business', value: false }
]
}
]
}
]
And i can extract the value that i want (the channel property) with this function:
setChannel(channel: string, source: string, language: string) {
for (const i of this.data) {
if (i.language === language) {
for (const j of i.sources) {
if (j.source === source) {
for (const k of j.channels) {
if (k.channel === channel) {
console.log(k.channel);
}
}
}
}
}
}
}
Now i'm sure that there is a function in lodash to simplify this. Because triple nested for's and if's is not a nice way of coding. But i can't seem to find it in the documentation. Could someone please point me in the right direction?
Lodash's filter() and flatMap() will get you there:
const result = _(data).filter({language: 'Dutch'})
.flatMap('sources')
.filter({source: 'De Redactie'})
.flatMap('channels')
.find({channel: 'sport'});
const data = [
{
language: 'Dutch',
sources: [
{
source: 'De Redactie',
channels: [
{ channel: 'binnenland', value: false },
{ channel: 'buitenland', value: false },
{ channel: 'sport', value: false },
{ channel: 'cultuur en media', value: false },
{ channel: 'politiek', value: false },
{ channel: 'financien', value: false }
]
},
{
source: 'Tweakers',
channels: [
{ channel: 'hardware', value: false },
{ channel: 'software', value: false },
{ channel: 'tech', value: false },
{ channel: 'smartphones', value: false },
{ channel: 'audio', value: false },
{ channel: 'video', value: false }
]
}
]
},
{
language: 'English',
sources: [
{
source: 'BBC',
channels: [
{ channel: 'news', value: false },
{ channel: 'sport', value: false },
{ channel: 'weather', value: false },
{ channel: 'travel', value: false },
{ channel: 'politics', value: false }
]
},
{
source: 'Fox News',
channels: [
{ channel: 'u.s.', value: false },
{ channel: 'world', value: false },
{ channel: 'opinion', value: false },
{ channel: 'politics', value: false },
{ channel: 'entertainment', value: false },
{ channel: 'business', value: false }
]
}
]
}
]
const result = _(data).filter({language: 'Dutch'})
.flatMap('sources')
.filter({source: 'De Redactie'})
.flatMap('channels')
.filter({channel: 'sport'})
.first();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
That's actually a pretty "quick & dirty" solution, because I didn't use any fallback default values. But you can read the docs about .find and .get.
const data = [{
language: 'Dutch',
sources: [{
source: 'De Redactie',
channels: [{
channel: 'binnenland',
value: false
},
{
channel: 'buitenland',
value: false
},
{
channel: 'sport',
value: false
},
{
channel: 'cultuur en media',
value: false
},
{
channel: 'politiek',
value: false
},
{
channel: 'financien',
value: false
}
]
},
{
source: 'Tweakers',
channels: [{
channel: 'hardware',
value: false
},
{
channel: 'software',
value: false
},
{
channel: 'tech',
value: false
},
{
channel: 'smartphones',
value: false
},
{
channel: 'audio',
value: false
},
{
channel: 'video',
value: false
}
]
}
]
},
{
language: 'English',
sources: [{
source: 'BBC',
channels: [{
channel: 'news',
value: false
},
{
channel: 'sport',
value: false
},
{
channel: 'weather',
value: false
},
{
channel: 'travel',
value: false
},
{
channel: 'politics',
value: false
}
]
},
{
source: 'Fox News',
channels: [{
channel: 'u.s.',
value: false
},
{
channel: 'world',
value: false
},
{
channel: 'opinion',
value: false
},
{
channel: 'politics',
value: false
},
{
channel: 'entertainment',
value: false
},
{
channel: 'business',
value: false
}
]
}
]
}
];
const setChannel = (channel = '', source = '', language = '') => {
// get all sources for the given language
const sourcesForLanguage = _.get(_.find(data, ['language', language]), 'sources');
// get all channels for given source
const channelsForSource = _.get(_.find(sourcesForLanguage, ['source', source]), 'channels');
// get the channel object for given channel
const selectedChannel = _.find(channelsForSource, ['channel', channel]);
console.log(selectedChannel);
}
setChannel('news', 'BBC', 'English');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
How to find user_value closest value from this array?
Here is user_value variable according to this i need find out closest value from array.
var user_value = 5500;
var array = [
{_id: 5809e269d60f577ae35f6add,
coins: 1000,
is_active: 1,
iconId: 4 },
{_id: 5809e269d60f577ae35f6ade,
coins: 2000,
is_active: 1,
iconId: 5 },
{_id: 5809e269d60f577ae35f6adf,
coins: 5000,
is_active: 1,
iconId: 6 },
{_id: 5809e269d60f577ae35f6ae0,
coins: 7000,
is_active: 1,
iconId: 7 },
{_id: 5809e269d60f577ae35f6ae1,
coins: 10000,
is_active: 1,
iconId: 8 },
{_id: 5809e269d60f577ae35f6ae2,
coins: 15000,
is_active: 1,
iconId: 9 } ];
You could use an iterative approach by using the absolute difference for checking.
var value = 5500,
array = [{ _id: '5809e269d60f577ae35f6add', coins: 1000, is_active: 1, iconId: 4 }, { _id: '5809e269d60f577ae35f6ade', coins: 2000, is_active: 1, iconId: 5 }, { _id: '5809e269d60f577ae35f6adf', coins: 5000, is_active: 1, iconId: 6 }, { _id: '5809e269d60f577ae35f6ae0', coins: 7000, is_active: 1, iconId: 7 }, { _id: '5809e269d60f577ae35f6ae1', coins: 10000, is_active: 1, iconId: 8 }, { _id: '5809e269d60f577ae35f6ae2', coins: 15000, is_active: 1, iconId: 9 }],
result = array.reduce(function (r, a, i, aa) {
return i && Math.abs(aa[r].coins - value) < Math.abs(a.coins - value) ? r : i;
}, -1);
console.log(result);
Assuming you define the closest as Math.abs(array[i].coins - value);, you just need to iterate the array like below:
var user_value = 5500;
var array = [
{
coins: 1000,
is_active: 1,
iconId: 4
},
{
coins: 2000,
is_active: 1,
iconId: 5
},
{
coins: 5000,
is_active: 1,
iconId: 6
},
{
coins: 7000,
is_active: 1,
iconId: 7
},
{
coins: 10000,
is_active: 1,
iconId: 8
},
{
coins: 15000,
is_active: 1,
iconId: 9
}
];
function findClosest (value) {
// By default that will be a big number
var closestValue = Infinity;
// We will store the index of the element
var closestIndex = -1;
for (var i = 0; i < array.length; ++i) {
var diff = Math.abs(array[i].coins - value);
if (diff < closestValue) {
closestValue = diff;
closestIndex = i;
}
}
return closestIndex;
}
console.log("The closest index: " + findClosest(user_value));
var _ = require('underscore');
var user_value = 5500;
var array = [
{ _id: '5809e269d60f577ae35f6add',
coins: 1000,
is_active: 1,
iconId: 4 },
{ _id: '5809e269d60f577ae35f6ade',
coins: 2000,
is_active: 1,
iconId: 5 },
{ _id: '5809e269d60f577ae35f6adf',
coins: 5000,
is_active: 1,
iconId: 6 },
{ _id: '5809e269d60f577ae35f6ae0',
coins: 7000,
is_active: 1,
iconId: 7 },
{ _id: '5809e269d60f577ae35f6ae1',
coins: 10000,
is_active: 1,
iconId: 8 },
{ _id: '5809e269d60f577ae35f6ae2',
coins: 15000,
is_active: 1,
iconId: 9 } ];
function getClosest(array, target) {
var tuples = _.map(array, function(json) {
return [json, Math.abs(json.coins - target)];
});
//console.log(tuples);
return _.reduce(tuples, function(memo, val) {
return (memo[1] < val[1]) ? memo : val;
}, [-1, 999])[0];
}
console.log(getClosest(array, user_value))