Get Specific Key with Highest Value from a (JSON) Object - javascript

I'm getting data back from an API response and attempting to get the name of the pitch with the highest speed. Here is a sample of the API response.
{
page: 1,
total_pages: 4,
listings: [
{
name: "A.J. Burnett",
pitches: [
{
name: "4 Seam FB",
speed: 96,
control: 84,
},
{
name: "Knuckle Curve",
speed: 79,
control: 74,
},
{
name: "Sinker",
speed: 95,
control: 64,
},
{
name: "Changeup",
speed: 81,
control: 44,
}
]
},
{
name: "Joe Smitch",
pitches: [
{
name: "4 Seam FB",
speed: 91,
control: 82,
},
{
name: "Changeup",
speed: 69,
control: 44,
}
]
},
]
}
Here is what I've tried:
itemSet.forEach( (item) => {
let fastestPitch = Object.keys(item.pitches).reduce((a, b) => {
item.pitches[a] > item.pitches[b] ? item.pitches[a].name : item.pitches[b].name
});
});
However, this always returns the name of the LAST pitch in the array. I'm attempting to return the pitch with the highest speed.
Edit: I've also tried the following, but it returns an error.
itemSet.forEach( (item) => {
let fastestPitch = Object.keys(item.pitches).reduce((a, b) => {
item.pitches[a].speed > item.pitches[b].speed ? item.pitches[a].name : item.pitches[b].name
});
});
Error:
(node:80698) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'speed' of undefined

You can do something like this:
const data = {
page: 1,
total_pages: 4,
listings: [{
name: "A.J. Burnett",
pitches: [{
name: "4 Seam FB",
speed: 96,
control: 84,
},
{
name: "Knuckle Curve",
speed: 79,
control: 74,
},
{
name: "Sinker",
speed: 95,
control: 64,
},
{
name: "Changeup",
speed: 81,
control: 44,
}
]
},
{
name: "Joe Smitch",
pitches: [{
name: "4 Seam FB",
speed: 91,
control: 82,
},
{
name: "Changeup",
speed: 69,
control: 44,
}
]
},
]
}
const fastesPitches = data.listings.map(({ pitches }) => {
return pitches.reduce((a, c) => c.speed > a.speed ? c : a).name;
});
console.log(fastesPitches);

To extract the fastest of each, you can Array#map each of the entries in listings and then Array#reduce their entries in pitches like this:
let data = { page: 1, total_pages: 4, listings: [{ name: "A.J. Burnett", pitches: [{ name: "4 Seam FB", speed: 96, control: 84, }, { name: "Knuckle Curve", speed: 79, control: 74, }, { name: "Sinker", speed: 95, control: 64, }, { name: "Changeup", speed: 81, control: 44, } ] }, { name: "Joe Smitch", pitches: [{ name: "4 Seam FB", speed: 91, control: 82, }, { name: "Changeup", speed: 69, control: 44, } ] }, ] };
let fastestPitches = data.listings.map(obj => {
return obj.pitches.reduce((best, current) => {
return best.speed > current.speed ? best : current
}, {}).name
});
console.log(fastestPitches)
Note that when you reduce, the first argument (best, in this case) is the result of the previous callback. So if you return just the name, you won't know what the speed of it was. So, you traverse and compare the speeds, then return the entire object that was better. When this finishes, you get the name of the result.

You could take a complete dynamic approach which looks for any depth and return the object with the wanted highest property from the most nested objects.
function getHighest(object, key) {
return Object.values(object).reduce((r, o) => {
if (!o || typeof o !== 'object') return r;
if (key in o && (!r || r[key] < o[key])) return o;
var temp = getHighest(o, key);
if (temp && (!r || r[key] < temp[key])) return temp;
return r;
}, undefined);
}
var data = { page: 1, total_pages: 4, listings: [{ name: "A.J. Burnett", pitches: [{ name: "4 Seam FB", speed: 96, control: 84 }, { name: "Knuckle Curve", speed: 79, control: 74 }, { name: "Sinker", speed: 95, control: 64 }, { name: "Changeup", speed: 81, control: 44 }] }, { name: "Joe Smitch", pitches: [{ name: "4 Seam FB", speed: 91, control: 82 }, { name: "Changeup", speed: 69, control: 44 }] }] },
highest = getHighest(data, 'speed');
console.log(highest.name);
console.log(highest);

Related

Replace value in table based on another table

Is there a best practice in using arquero to reformat a value based on a set of ranges?
For example, I have the following 2 arrays:
const agefmt = [
{
'fmtname': 'agefmt',
'type' : 'n',
'format': [
{'start': 0, 'end': 10, 'label': '0 - 10'},
{'start': 11, 'end': 20, 'label': '11 - 20'},
{'start': 21, 'end': 30, 'label': '21 - 30'},
{'start': 31, 'end': 40, 'label': '31 - 40'},
{'start': 41, 'end': 50, 'label': '41 - 50'},
{'start': 51, 'end': 1000, 'label': '>51'}
]
},
]
const age = [
{ "AGE": 19 },
{ "AGE": 20 },
{ "AGE": 31 },
{ "AGE": 26 },
{ "AGE": 46 },
{ "AGE": 27 }
]
and I would like to replace the 'age' array with the 'label' within the range of the 'start' and 'end' values defined in the agefmt array.
The resulting array should look like the following:
[
{ "AGE": '0 - 10' },
{ "AGE": '11 - 20' },
{ "AGE": '31 - 40' },
{ "AGE": '21 - 30' },
{ "AGE": '41 - 60' },
{ "AGE": '21 - 30' }
]
I started writing it as a function like so, but found I couldn't pass the 'agefmt' as a parameter:
addFunction(function fmt({infmt, value}) {
console.log(value, infmt)
// calculate ranges here
return value
});
r.derive({rowvar : d => op.fmt(rowgrp, d.rowvar)})
Is there a more obvious way to achieve this?
It is just a matter of iterating through the age array, and then checking the nested AGE property against agefmt[0].format in a for loop. Whenever the AGE value is between the start and end values, then a label is considered found and we break out of the for loop.
One thing is that your expected output is incorrect based on your provided data: the first entry has an age of 19 and the matching label should be 11 - 20 not 0 - 10 as you wanted.
See proof-of-concept below:
const agefmt = [
{
fmtname: "agefmt",
type: "n",
format: [
{ start: 0, end: 10, label: "0 - 10" },
{ start: 11, end: 20, label: "11 - 20" },
{ start: 21, end: 30, label: "21 - 30" },
{ start: 31, end: 40, label: "31 - 40" },
{ start: 41, end: 50, label: "41 - 50" },
{ start: 51, end: 1000, label: ">51" },
],
},
];
const age = [
{ AGE: 19 },
{ AGE: 20 },
{ AGE: 31 },
{ AGE: 26 },
{ AGE: 46 },
{ AGE: 27 },
];
function addLabelToAge(age, labelFormat) {
return age.map(entry => {
let matchedLabel = '';
for (const format of labelFormat) {
if (entry.AGE >= format.start && entry.AGE <= format.end) {
matchedLabel = format.label;
break;
}
}
return { AGE: matchedLabel };
});
}
console.log(addLabelToAge(age, agefmt[0].format));
If you're comfortable with ES6 syntax, you can make the function a little more concise using object destructuring + object property assignment shorthand:
function addLabelToAge(age, labelFormat) {
return age.map(({ AGE }) => {
let matchedLabel = '';
for (const { start, end, label } of labelFormat) {
if (AGE >= start && AGE <= end) {
matchedLabel = label;
break;
}
}
return { AGE: matchedLabel };
});
}

Formatt array of obj

i have this array of obj
const pressure = [
{
date: "2021-11-03T23:51:55.875Z",
diastolica: 72,
pulsazione: 69,
sistolica: 130,
user: "61830313ba36bf2504df0ec3",
__v: 0,
_id: "6183209bf91a7ed54a76c05e",
},
{
date: "2021-11-03T23:52:09.684Z",
diastolica: 75,
pulsazione: 71,
sistolica: 135,
user: "61830313ba36bf2504df0ec3",
__v: 0,
_id: "618320a9f91a7ed54a76c061",
},
];
What I would like to get is an array of objects formatted like this
[
{
name: "Sistolica",
data: [130,135],
},
{
name: "Diastolica",
data: [72,75]
},
{
name: "Pulsazione",
data: [69,71],
},
],
For use within apex charts
The solution I found is not suitable and above all it is not reusable, if I passed an array that does not have the same keys that I indicated in my helper function, everything would be for the worse.
Can anyone help me with this?
I post the solution I had adopted, but I know it's really awful
export const setupGraphSeries = (data) => {
const sistolica = [];
const diastolica = [];
const pulsazione = [];
const formatter = data.map((item) => {
sistolica.push(item["sistolica"]);
diastolica.push(item["diastolica"]);
pulsazione.push(item["pulsazione"]);
return [
{ name: "Sistolica", data: sistolica },
{ name: "Diastolica", data: diastolica },
{ name: "Pulsazione", data: pulsazione },
];
});
return formatter;
};
One way is to just map over an array of the required properties. This does mean mapping over pressures once per item:
const pressure = [
{
date: "2021-11-03T23:51:55.875Z",
diastolica: 72,
pulsazione: 69,
sistolica: 130,
user: "61830313ba36bf2504df0ec3",
__v: 0,
_id: "6183209bf91a7ed54a76c05e",
},
{
date: "2021-11-03T23:52:09.684Z",
diastolica: 75,
pulsazione: 71,
sistolica: 135,
user: "61830313ba36bf2504df0ec3",
__v: 0,
_id: "618320a9f91a7ed54a76c061",
},
];
const params = ["diastolica","pulsazione","sistolica"];
const result = params.map( name => ({
name,
data: pressure.map(x => x[name])
}));
console.log(result);
Another way is to reduce the original keeping track of whether you have that item yet. This doesnt require multiple passes over the original data but is a little more complex:
const pressure = [
{
date: "2021-11-03T23:51:55.875Z",
diastolica: 72,
pulsazione: 69,
sistolica: 130,
user: "61830313ba36bf2504df0ec3",
__v: 0,
_id: "6183209bf91a7ed54a76c05e",
},
{
date: "2021-11-03T23:52:09.684Z",
diastolica: 75,
pulsazione: 71,
sistolica: 135,
user: "61830313ba36bf2504df0ec3",
__v: 0,
_id: "618320a9f91a7ed54a76c061",
},
];
const params = ["diastolica","pulsazione","sistolica"];
const result = Object.values(pressure.reduce( (a,item) => {
for(var i=0;i<params.length;i++){
const name = params[i];
a[name] = a[name] || {name,data:[]}
a[name].data.push(item[name]);
}
return a;
},{}));
console.log(result);

Modify array of objects to replace with additional properties if null

I have an array of object as follows
let data = [
{
vertical_name: "CORE",
projects: [
{
name: "Alpha",
id: 187,
current_result: null,
}
]
},
{
vertical_name: "release",
projects: [
{
name: "Beta",
id: 27,
current_result: {
success_percentage: 37,
failure_percentage: 25,
skip_percentage: 36
}
},
{
name: "Charlie",
id: 47,
current_result: {
success_percentage: 37,
failure_percentage: 25,
skip_percentage: 36
}
}
]
}
]
As you can see current_result is null at one place. So i have to modify data to show that current_result is not tested. So in this case, instead of showing null, i want to show as follows. not_tested is 100 and skip, failure and success percentage is 0 in this case.
current_result: {
success_percentage: 0,
failure_percentage: 0,
skip_percentage: 0,
not_tested: 100
}
Also on other values of current_result, since it is not null and has success, failure and skip values, not_tested should be 0 for this.
The final result should look something like this. can someone please let me know how to achieve this as it is slightly complicated for me to come to a definitive answer
result = [
{
vertical_name: "CORE",
projects: [
{
name: "Alpha",
id: 187,
current_result: {
success_percentage: 0,
failure_percentage: 0,
skip_percentage: 0,
not_tested: 100
}
}
]
},
{
vertical_name: "release",
projects: [
{
name: "Beta",
id: 27,
current_result: {
success_percentage: 37,
failure_percentage: 25,
skip_percentage: 36,
not_tested: 0
}
},
{
name: "Charlie",
id: 47,
current_result: {
success_percentage: 37,
failure_percentage: 25,
skip_percentage: 36,
not_tested: 0
}
}
]
}
]
You could loop into data's projects array and insert keys you want in this way:
let data = [ { vertical_name: "CORE", projects: [ { name: "Alpha", id: 187, current_result: null, } ] }, { vertical_name: "release", projects: [ { name: "Beta", id: 27, current_result: { success_percentage: 37, failure_percentage: 25, skip_percentage: 36 } }, { name: "Charlie", id: 47, current_result: { success_percentage: 37, failure_percentage: 25, skip_percentage: 36 } } ] } ]
data.forEach(dat => {
dat.projects.forEach(prj => {
if (!prj.current_result) {
prj.current_result = {
success_percentage: 0,
failure_percentage: 0,
skip_percentage: 0,
not_tested: 100
};
}
else {
prj.current_result.not_tested = 0;
}
})
})
console.log(data)
Using Array#map without mutating the original data
const data = [{"vertical_name":"CORE","projects":[{"name":"Alpha","id":187,"current_result":null}]},{"vertical_name":"release","projects":[{"name":"Beta","id":27,"current_result":{"success_percentage":37,"failure_percentage":25,"skip_percentage":36}},{"name":"Charlie","id":47,"current_result":{"success_percentage":37,"failure_percentage":25,"skip_percentage":36}}]}];
const formatted = data.map(item => Object.assign(item, {
projects: item.projects.map(project => {
if (project.current_result === null) {
project.current_result = {
success_percentage: 0,
failure_percentage: 0,
skip_percentage: 0,
not_tested: 100
};
} else project.current_result.not_tested = 0;
return project;
})
}));
console.log(formatted);
let data = [{vertical_name: "CORE",projects: [{name: "Alpha",id: 187, current_result: null,}]},{vertical_name: "release", projects: [{ name: "Beta", id: 27, current_result: { success_percentage: 37, failure_percentage: 25, skip_percentage: 36}},{name: "Charlie", id: 47, current_result: { success_percentage: 37, failure_percentage: 25, skip_percentage: 36}}]}]
const newData = data.map((element)=>{
return element.projects.map((project)=>{
if(project.current_result === null){
return {...project, current_result: {success_percentage: 0,
failure_percentage: 0,
skip_percentage: 0,
not_tested: 100
}
}
}
return {...project, current_result: {...project.current_result, not_tested: 0} }
})
})
console.log(newData)
you can try this code :
data.map((element)=>{
element.projects.map((project)=>{
if(project.current_result === null){
return {...project, current_result: {success_percentage: 0,
failure_percentage: 0,
skip_percentage: 0,
not_tested: 100
}
}
}
return {...project, current_result: {...project.current_result, not_tested: 0} }
})
})
You can filter out your result data and assign a default value.
const result = data.map((item) => {
const projects = item.projects.map((project) => {
if (!project?.current_result) {
return {
...project,
current_result: {
success_percentage: 0,
failure_percentage: 0,
skip_percentage: 0,
not_tested: 100,
},
};
} else {
return project;
}
});
console.log(result)

How to merge duplicate array?

const data =
[{notification_id: 124, user_id: 10, story_id: 25, string: "liked on your story" }
{notification_id: 125, user_id: 12, story_id: 25, string: "liked on your story" }
{notification_id: 126, user_id: 15, story_id: 25, string: "liked on your story" }]
output: user 10,12 and 15 liked on your story ID 25
I want to show output like above. How to merge and show those like the output. Any idea?
You need to create a hash map, check the code snippet below:
const allData = [
{ name: 'John', story: 1 },
{ name: 'Ross', story: 2 },
{ name: 'Taylor', story: 1 },
{ name: 'Jimmy', story: 2 },
{ name: 'Amanda', story: 3 },
];
const hash = {};
for (let data of allData) {
if (data.story in hash) hash[data.story] = [...hash[data.story], { ...data }];
else hash[data.story] = [{ ...data }];
}
console.log(hash);
You should use Map, which is what I would suggest. The code below does the same thing but using Maps.
const allData = [
{ name: 'John', story: 1 },
{ name: 'Ross', story: 2 },
{ name: 'Taylor', story: 1 },
{ name: 'Jimmy', story: 2 },
{ name: 'Amanda', story: 3 },
];
const hash = new Map();
for(let data of allData) {
const currentVal = hash.get(data.story);
if (currentVal) hash.set(data.story, [...currentVal, {...data}])
else hash.set(data.story, [{...data}])
}
console.log(hash);
I cann't comment. So i write here!
Are you wanting ...
result = [
{
story_id : 25,
user_id : [10, 12, 15]
}
]
Right?
This is solution of me
const data =
[{notification_id: 124, user_id: 10, story_id: 25, string: "liked on your story" }
{notification_id: 125, user_id: 12, story_id: 25, string: "liked on your story" }
{notification_id: 126, user_id: 15, story_id: 25, string: "liked on your story" }]
var result = data.reduce((res, item) => {
let storyID = item.story_id;
if (typeof res[storyID] == 'undefined') {
res[storyID] = {
story_id: storyID,
user_id: []
}
}
res[storyID].user_id.push(item.user_id);
return res;
}, []);
result = Object.values(result);

The output of the below code is NaN, Why? [duplicate]

This question already has answers here:
Calling reduce to sum array of objects returns NaN
(2 answers)
Closed 3 years ago.
Here, i am trying to add 'order_total' property. I have used reduce method, if try for only arrays, the same code is working properly, but when i implemented on array of objects it is resulting NaN.
var user = {
id: 16,
username: 'smith',
email: 'smith#gmail.com',
order: [
{
id: 71,
order_number: 'DCT-123',
order_total: 12000,
},
{
id: 71,
order_number: 'DCT-345',
order_total: 7000,
},
{
id: 71,
order_number: 'DCT-321',
order_total: 2000,
}
]
};
var result = user.order.reduce(function(a, b) {
return a.order_total + b.order_total;
});
console.log(result);
The parameter a in the reduce callback is the accumulator, not the property of the object. Refer here to learn more about reduce
var user = {
id: 16,
username: 'smith',
email: 'smith#gmail.com',
order: [
{
id: 71,
order_number: 'DCT-123',
order_total: 12000,
},
{
id: 71,
order_number: 'DCT-345',
order_total: 7000,
},
{
id: 71,
order_number: 'DCT-321',
order_total: 2000,
}
]
};
var result = user.order.reduce(function(a, b) {
return a+b.order_total;
},0);
console.log(result);
You return a number, not an object.
var result = user.order.reduce(function(a, b) {
// ^ object
// ^ object
return a.order_total + b.order_total; // number
});
You need a start value of zero and add the value of the property.
var user = {
id: 16,
username: 'smith',
email: 'smith#gmail.com',
order: [
{
id: 71,
order_number: 'DCT-123',
order_total: 12000,
},
{
id: 71,
order_number: 'DCT-345',
order_total: 7000,
},
{
id: 71,
order_number: 'DCT-321',
order_total: 2000,
}
]
};
var result = user.order.reduce(function(total, a) {
return total + a.order_total;
}, 0);
console.log(result);

Categories

Resources