4
\$\begingroup\$

I'm using the matomo reports api to pull out some data in js. For some charts, I'm in the need to sort the array data based on inner property value ("val"), further to get only the 3 highest (Hong Kooong, Munich, Tokyo). Finally, this data should be used for the creation of a new key/val object (newObj).

This is what my code looks like what does what it should. I would be interested if it can be optimized using es6 syntax.

 let data = {
 0 : {"label":"New York", "val": 20},
 1 : {"label":"Rio", "val": 10},
 3 : {"label":"Tokyo", "val": 50},
 4 : {"label":"Santiago", "val": 20},
 5 : {"label":"Hong Kooong", "val": 100},
 6 : {"label":"Munich", "val": 90},
 }
 
 let compare = (a, b) => {
 let valA = a.val;
 let valB = b.val;
 let c = 0;
 
 if (valA > valB) {
 c = 1;
 } else if (valA < valB) {
 c = -1;
 }
 return c * -1;
 }
 
 let dataArray = Object.values(data).sort(compare)
 dataArray = dataArray.slice(0, 3)
 
 let newLabel = []
 let newValue = []
 Object.keys(dataArray).map(function(key, index) {
 newLabel.push(dataArray[index]['label'])
 newValue.push(dataArray[index]['val'])
 });
 
 let newObj = {}
 newObj.data = {}
 newObj.data.labels = newLabel
 newObj.data.values = newValue
 
 console.log(newObj)

asked Aug 19, 2019 at 16:11
\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

Let's start with how I would have done it.

const data = {
 0 : {"label":"New York", "val": 20},
 1 : {"label":"Rio", "val": 10},
 3 : {"label":"Tokyo", "val": 50},
 4 : {"label":"Santiago", "val": 20},
 5 : {"label":"Hong Kooong", "val": 100},
 6 : {"label":"Munich", "val": 90},
}
const result = Object.values(data)
 .sort((a, b) => b.val - a.val)
 .slice(0, 3)
 .reduce((c, v) => {
 c.data.labels.push(v.label)
 c.data.values.push(v.val)
 return c
 }, { data: { labels: [], values: []}})
 
console.log(result)

Now onto your code:

let dataArray = Object.values(data).sort(compare)
dataArray = dataArray.slice(0, 3)

You were off to a good start here. One minor nitpick is to just chain the operations since you're just reassigning dataArray with sort's results.

let newLabel = []
let newValue = []
Object.keys(dataArray).map(function(key, index) {
 newLabel.push(dataArray[index]['label'])
 newValue.push(dataArray[index]['val'])
});
let newObj = {}
newObj.data = {}
newObj.data.labels = newLabel
newObj.data.values = newValue

This is where it went crazy.

Firstly, you used Object.keys() on dataArray (an array), which is not needed. If you need the array item index, all of the array methods provide the item index as second argument of the callback.

Also, this is a bad use of array.map(). array.map() is used to transform values in one array to another array of values, i.e. a 1:1 transform operation. In this case, you're merely using it for looping, something better suited for array.forEach().

Since you're "reducing"/"aggregating" an array of values into one value (turning an array of values into an object), array.reduce() is the better option.

answered Aug 19, 2019 at 16:42
\$\endgroup\$
0
4
\$\begingroup\$

Your compare function can be simplified a bit using Math.sign:

let compare = (a, b) => {
 return -Math.sign(a.val - b.val);
}

sign will return one of -1, 0, or 1, which correspond to the sign of the number passed to it. This is basically what you were doing manually. Most languages have a sign (or signum) function for cases like this.

I also used a unary prefix - to negate instead of using * -1. As an alternative, you could change it to just:

let compare = (a, b) => {
 return Math.sign(b.val - a.val); // a and b were swapped
}

Which will have the same effect. It depends on what looks more readable to you.


I'll leave it off there as someone else went in depth.

answered Aug 19, 2019 at 16:44
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.