Extract data from an array of Object - javascript

I have this array of Object that I am getting from my database:
[Array of Object][1]
I would like to make an array of array for each value, but I can't manage to find a way to do it as I'm a beginner of javascript.
For example :
var Stats=[
[39,49,43,42,41,35], //SGW Value for each Object
[37,44,49,46,52,42], //UD Value for each Object
[8,11,8,8,16,15], //Virtual Value for each Object
...
]
The goal is to make a chart on chart.js that look like that :
[Chart Goal][2]
I would need to loop the dataset because I'll add more data and it would be way too long to set each dataset individually.
Thanks for your time.

You can do it like this:
let array1 = [
{
param1: 10,
param2: 20
},
{
param1: 30,
param2: 40
}
]
let array2 = array1.map(item => Object.values(item));
console.log(array2); // prints [[10, 20], [30, 40]]

First of all you need to create an array for each property you want to plot; i.e.:
var fsp = [],
msg = [],
sgw = [];
Then you can loop over your dataset and put the data in each array:
yourArray.forEach(function(obj){
//obj takes the value of each object in the database
fsp.push(obj.fsp);
msg.push(obj.msg);
sgw.push(obj.sgw);
})
or, if you are more familiar with for loop
for(var obj of yourArray){
fsp.push(obj.fsp);
msg.push(obj.msg);
sgw.push(obj.sgw);
}
Finally you can create an array as you pointed in your example
var result = [];
result.push(fsp, msg, sgw);
And the result will be
[
[89, 59, 43, 60, 81, 34, 28, 58, 75, 41],
[77, 91, 4, 56, 6, 1, 42, 82, 97, 18],
[24, 34, 4, 13, 75, 34, 14, 41, 20, 38]
]
For more informations take a look at Array.forEach(), Array.push() and for...of documentations
EDIT
As you pointed in your comment, you can generate arrays dynamically creating an object like var arrays = {};. Then in forEach(), or if for...of, you need to loop over objects with a for...in loop. The variable you declare in loop's head takes the value of index, numeric for Arrays, literal for Objects. You have to do something like:
yourArray.forEach(function(obj){
for(let index in obj){
if(!arrays[index]) // check if property has already been set and initialized
arrays[index] = []; // if not, it's initialized
arrays[index].push(obj[index]) // push the value into the array
}
})
Note that Object has been treated as Array because you access its properties with a variable filled at runtime.
The result will be:
arrays = {
fsp: [89, 59, 43, 60, 81, 34, 28, 58, 75, 41],
msg: [77, 91, 4, 56, 6, 1, 42, 82, 97, 18],
sgw: [24, 34, 4, 13, 75, 34, 14, 41, 20, 38]
}
To obtain only arrays use Object.values().
If you cannot imagine how this works, I suggest you to make some examples in Chrome Developer Tools' console, or in Node's console, or wherever you can have a realtime feedback, putting in the middle of code some console.log() of variables

Related

How to dynamically calculate the array of object values in Javascript?

I have input format as below,
var boxplotInput = [{Day: "01-07-2021", "Thomas": 95, "Diana": 94, "Claura": 93, "Chandler": 93},
{Day: "02-07-2021", "Thomas": 95, "Diana": 94, "Claura": 94, "Chandler": 94},
...
...
{Day: "31-07-2021", "Thomas": 92, "Diana": 94, "Claura": 93, "Chandler": 91}];
I am quite new to javascript objects handling. I have written the code as below to calculate Q1, Q3, and median and it is working fine mathematically the way I am expecting.
//Getting the list of students (excluding date)
var keys;
for(var i = 0; i <boxplotInput.length; i++ ){
keys = Object.keys(boxplotInput[i]).slice(1);
}
////Here, I am hard-coding keys[0]. and getting "Thomas" data only. I am not getting how to avoid for one students only and achieve it for all students.
var studentDataSample = [];
for(var i = 0; i <boxplotInput.length; i++ ){
student1 = boxplotInput[i][keys[0]];
studentDataSample.push(student1);
}
studentDataSample.sort(function(a, b) {return a - b;});
var length = studentDataSample.length;//31
var midIndex = middleIndex(studentDataSample, 0, length);//16
var medianValue = studentDataSample[midIndex];
var Q1 = studentDataSample[middleIndex(studentDataSample, 0, midIndex)];
var Q3 = studentDataSample[middleIndex(studentDataSample, midIndex + 1, length)];
console.log(Q1+", "+medianValue+", "+Q3);// here, the values are fine.
function middleIndex(data, initial, length){
var n = length - initial + 1;
n = parseInt((n + 1) / 2);
return parseInt(n + initial);
}
Something, I understand that it could be achievable through the loop again.. but, not getting how to achieve it for all the students. Kindly, provide the suggestion or idea on this.
Thanks in advance.
if I understand you correctly all need following JS methods:
Array.reduce
Array.filter
Object.keys
The main thing you need here is create useful collection of students with their grades. After this you can calculate all the things you want. In this example I show how to calculate mean.
var boxplotInput = [
{Day: "01-07-2021", "Thomas": 95, "Diana": 94, "Claura": 93, "Chandler": 93},
{Day: "02-07-2021", "Thomas": 95, "Diana": 94, "Claura": 94, "Chandler": 94},
{Day: "31-07-2021", "Thomas": 92, "Diana": 94, "Claura": 93, "Chandler": 91}
];
/*
Get collection of students like:
{
Thomas: [ 95, 95, 92 ],
Diana: [ 94, 94, 94 ],
Claura: [ 93, 94, 93 ],
Chandler: [ 93, 94, 91 ]
}
*/
const students = boxplotInput.reduce((accumulator, currentDay) => {
const students = Object
.keys(currentDay)
.filter(el => el !== 'Day');
students.forEach(student => {
if (!accumulator[student]) {
accumulator[student] = [];
}
accumulator[student].push(currentDay[student]);
});
return accumulator;
}, {});
console.log('Student grades:', students);
// Then we can do anything with it
const studentNames = Object.keys(students);
// Example: finding mean
const studentMeans = studentNames.reduce((acc, student) => {
const grades = students[student];
const sumOfGrades = grades.reduce((acc, cur) => cur + acc, 0);
acc[student] = sumOfGrades / grades.length;
return acc;
}, {});
console.log('Means:', studentMeans);
/*
{
Thomas: 94,
Diana: 94,
Claura: 93.33333333333333,
Chandler: 92.66666666666667
}
*/
I will show you a very clean way to do this using Underscore. Let's inspect all the tools that Underscore and JavaScript provide for this purpose and build our solution one step at a time.
A nice function from Underscore is chain, which lets us massage data in a different shape step by step, while keeping the code very easy to read. For example, you can probably guess what the following chain will do:
var sortedLast = _.chain([2, 3, 1])
.sort()
.last();
console.log(sortedLast);
<script src="https://underscorejs.org/underscore-umd-min.js"></script>
chain creates a special wrapper around the input data, which has all Underscore functions as methods. Each method returns a new wrapper, so you can continue to apply more Underscore functions. At the end, you can unwrap the result by calling .value(). In some cases, like in the example above, this happens automatically. last returns the last element of an array.
A nice end shape, which we might want to work towards, could be the following:
{
Thomas: {min: 92, Q1: 93.5, median: 95, Q3: 95, max: 95},
Diana: {min: 94, Q1: 94, median: 94, Q3: 94, max: 94},
Claura: {min: 93, Q1: 93, median: 93, Q3: 93.5, max: 94},
Chandler: {min: 91, Q1: 92, median: 93, Q3: 93.5, max: 94},
}
This is an object which has the same keys as every element of boxplotInput, except for Day. Underscore has an omit function, which lets us do this cleanly, without having to rely on the keys appearing in a particular order:
_.chain(boxplotInput[0])
.omit('Day');
// {Thomas: 95, Diana: 94, Claura: 93, Chandler: 93}
Now we have an object with the correct keys, but wrong values.
mapObject lets us create a new object with the same keys but different values. Besides the input object, it takes a function which will be applied to every key-value pair of the input object in turn. That function takes the value as the first argument and the key as the second argument. Its return value becomes the value at the corresponding key in the new object.
As an intermediate step, let's create an object with a list of all scores per student:
{
Thomas: [95, 95, 92],
Diana: [94, 94, 94],
Claura: [93, 94, 93],
Chandler: [93, 94, 91],
}
In order to achieve this with mapObject, we need to write a function that, given the name of a student, returns an array with the student's scores. Its start will look like this:
function studentScores(firstScore, studentName) {
// code here
}
Let's look at an elegant way to get those scores. In your original code, you wrote something like this (but with key[0] instead of studentName):
var studentDataSample = [];
for (var i = 0; i < boxplotInput.length; i++) {
var student1 = boxplotInput[i][studentName];
studentDataSample.push(student1);
}
Underscore lets you get the same result in a very short line using map:
var studentDataSample = _.map(boxplotInput, studentName);
JavaScript's arrays nowadays have a built-in map method which lets you do something similar. It is not as flexible and concise as Underscore's map, but I'll show how to use it for completeness:
var studentDataSample = boxplotInput.map(dayScores => dayScores[studentName]);
We now know how to write our studentScores:
function studentScores(firstScore, studentName) {
return _.map(boxplotInput, studentName);
}
We don't need the firstScore, but we have to accept it as the first argument anyway, because we are going to pass this function to mapObject, which always passes the value first. Fortunately, we can just ignore it. We can write this function more concisely using the new arrow notation:
(fs, studentName) => _.map(boxplotInput, studentName)
Now we can include this function in our chain, in order to arrive at the intermediate result we previously discussed:
_.chain(boxplotInput[0])
.omit('Day')
.mapObject((fs, studentName) => _.map(boxplotInput, studentName));
// {
// Thomas: [95, 95, 92],
// Diana: [94, 94, 94],
// Claura: [93, 94, 93],
// Chandler: [93, 94, 91]
// }
Let's sort the scores as well, as a preparation for computing the quantiles:
_.chain(boxplotInput[0])
.omit('Day')
.mapObject((fs, studentName) => _.map(boxplotInput, studentName).sort());
// {
// Thomas: [92, 95, 95],
// Diana: [94, 94, 94],
// Claura: [93, 93, 94],
// Chandler: [91, 93, 94]
// }
We can add another mapObject to the chain in order to transform these arrays of sorted scores to the final {min, Q1, median, Q3, max} objects we were aiming for. Since this is not really what your question was about, I will just propose one possible way to do it in functional style:
// A function that returns a function (this is not a typo) that
// computes a particular quantile from a sorted array of numbers.
function quantile(fraction) {
return function(numbers) {
var middle = (numbers.length - 1) * fraction;
return (numbers[Math.floor(middle)] + numbers[Math.ceil(middle)]) / 2;
};
}
// A "blueprint" object with the keys we want to have, each having a
// function to compute the corresponding value from a sorted array of
// scores.
var quantileComputations = {
min: _.first,
Q1: quantile(.25),
median: quantile(.5),
Q3: quantile(.75),
max: _.last,
};
// A function that applies the above blueprint to a given array of
// numbers.
function getQuantiles(numbers) {
return _.mapObject(quantileComputations, f => f(numbers));
}
// Redefining the input data to make this snippet runnable.
var boxplotInput = [
{Day: "01-07-2021", "Thomas": 95, "Diana": 94, "Claura": 93, "Chandler": 93},
{Day: "02-07-2021", "Thomas": 95, "Diana": 94, "Claura": 94, "Chandler": 94},
{Day: "31-07-2021", "Thomas": 92, "Diana": 94, "Claura": 93, "Chandler": 91},
];
// Completing our chain using the above.
var statistics = _.chain(boxplotInput[0])
.omit('Day')
.mapObject((fs, studentName) => _.map(boxplotInput, studentName).sort())
.mapObject(getQuantiles)
.value();
console.log(statistics);
<script src="https://underscorejs.org/underscore-umd-min.js"></script>

Array sorting for Object Keys not working

Could someone please help me sort object by key with given array?
given array ['NAME',20200229,20200131,20200331]
given object {20200131: 51, 20200229: 50, 20200331: 170, NAME: "a"}
Object.fromEntries was expected to build object in the given keys
Object.fromEntries(Object.entries({b: 3, a:8, c:1}))
//{b: 3, a: 8, c: 1} <-- works fine
But when I try with keys that has number and alphanumerics it's doesn't work
let sortingArr = ['NAME',20200229,20200131,20200331] // desired sort, for example
// All below gives the same result
Object.fromEntries(Object.entries({NAME: 'a',20200131: 51, 20200229: 50, 20200331: 170}))
// sort asc naturally,.. ok
Object.fromEntries(Object.entries({NAME: 'a',20200131: 51, 20200229: 50, 20200331: 170}).sort())
// sort asc naturally,.. redundant... ok, no problems
Object.fromEntries(Object.entries({NAME: 'a',20200131: 51, 20200229: 50, 20200331: 170}).sort((a, b)=> parseInt(a)||0 + sortingArr.indexOf(b)))
//Problem! was supose to consider the sorting logic*, right?
//*Sorting works: Object.entries({NAME: 'a',20200131: 51, 20200229: 50, 20200331: 170}).sort((a, b)=> parseInt(a)||0 + sortingArr.indexOf(b))
//0: ["NAME", "a"]
//1: ["20200131", 51]
//2: ["20200229", 50]
//3: ["20200331", 170]
I read other responses and they are very redundant, with people wanting only in ascending (or descending) order, without the desired array

How to create a variable that is the lowest possible number?

What I have here is an algorithm that finds the highest value in each subarray and pushes it onto a separate array (final).
I want to let the variable 'value' equal to the lowest possible number so that any negative number can be considered higher than 'value'
function largestOfFour(arr) {
var final=[];
arr.map(sub => {
let value = 0; //issue
sub.map(num => {
if(num>value){value=num};
})
final.push(value)
})
return final;
}
console.log(largestOfFour([[17, 23, 25, 12], [25, 7, 34, 48], [4, -10, 18, 21], [-72, -3, -17, -10]]));
In this example the last subarray returns 0 since non of the numbers in that subarray were higher than the initial value of 'value' which is 0.
I want it to return '-3' instead since it's the highest number in the subarray.
It would appear you're simply looking for the max of each array.
Using Array#map and Math#max and spread syntax you could do something like this.
const data = [[17, 23, 25, 12], [25, 7, 34, 48], [4, -10, 18, 21], [-72, -3, -17, -10]];
const res = data.map(arr=>Math.max(...arr));
console.log(res);
You can just set value to Number.NEGATIVE_INFINITY but for what it's worth, I'd recommend simply using reduce instead of map in your inner function. That way, the inner loop will start with sub[0] as an initial value rather than depending on any placeholder.
function largestOfFour(arr) {
var final = arr.map(sub => sub.reduce((num, value) => Math.max(num, value)));
return final;
}
console.log(largestOfFour([
[17, 23, 25, 12],
[25, 7, 34, 48],
[4, -10, 18, 21],
[-72, -3, -17, -10]
]));

Pairing multiple javascript arrays

I'm trying to solve a problem I have with multiple javascript arrays.
So basically the result I want is to match the arrays of a dropdown box with other values from other arrays that I will display.
The arrays contain different values, but the order is the most important thing
var array1 = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22];
var array2 = [30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50];
var array3 = [36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56];
Let's say the user selects number 4, then I need to somehow select 32 in array2 and 38 in array3.
Any suggestions are gladly accepted, Thanks!
Get the index from the first array, with Array.prototype.indexOf
var index = array1.indexOf(4);
Get the values from other arrays with that index, like this
console.log(array2[index], array3[index]);
Note: If the value being searched is not found in the array, indexOf will not fail with an error but it will simply return -1. So, you might want to check before using that to access the elements from other arrays, like this
var index = array1.indexOf(4);
if (index !== -1) {
console.log(array2[index], array3[index]);
} else {
console.log("Invalid element selected");
}
Any time you have multiple parallel arrays, you should really consider refactoring it into a single array of objects. That way you never have to worry about keeping them synched. For example:
var myArray = [ { val1: 2, val2: 30, val3: 36 }, { val1: 4, val2: 32, val3: 38 }, ...];
Now to find the value for 4 you can simply do something like (although a simple for loop might be more efficient since you know there is only ever one result):
var myValues = myArray.filter(function(item) { return item.val1 === 4 });
And then access myValues[0].val2 and myValues[0].val3.
Or, if you are always looking up by the first value, you can use that as your key for an object that maps to your other two values. Something like:
var myArray = { 2: { val2: 30, val3: 36 }, 4: { val2: 32, val3: 38 },...};
Now if you want the other two values for 4 you can simply:
var value2 = myArray[4];
var value3 = myArray[4];
Assuming those are not only arrays and values, but you have actual <select> dropdown boxes:
Accessing the selected value is not only possible by using select1.value, but also by using select1.options[select1.selectedIndex].value. That.selectedIndex is what we are interested in, and you can use that equivalently on the option collections of the other two dropdowns, or the arrays with their values:
select2.options[select1.selectedIndex].value
array2[select1.selectedIndex]
select3.options[select1.selectedIndex].value
array3[select1.selectedIndex]
If you access them via the options collection you will need to make sure that one option is actually selected (select1.selectedIndex != -1), otherwise you'd get an exception.
Do it like this,
var valueFromSelect = 4;
var array1 = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22];
var array2 = [30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50];
var array3 = [36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56];
for(var i = 0; i < array1.length; i++){
if(valueFromSelect == array1[i]){
console.log(array2[i], array3[i]);
break;
}
}
I suggest you don't use indexOf, it's not compatible with IE < 9 read more about that here indexOf MDN

Split a string array into a number array in javascript

I am reading a value from a dropdown list depending on what option is selected. I am using jqPlot to graph the values.
jqPlot expects an array of values like [91, 6, 2, 57, 29, 40, 95]
but when I read the value in from the dropdown box it is coming in as a whole string "[91, 6, 2, 57, 29, 40, 95]"
I tried splitting it but I got ["91", "6", "2", "57", "29", "40", "95"] which wont display the graph correctly.
Is there anybody that has encountered something like this before and what can I do to make my values convert into a number array.
Thanks for any help
You can use JSON.parse() to convert that string into a JavaScript array. The numbers in the string are not quoted so the array will also contain numbers. And you can delete all the code that parses the string as you won't need it anymore.
>>> JSON.parse("[91, 6, 2, 57, 29, 40, 95]")
[91, 6, 2, 57, 29, 40, 95]
If you need to support legacy browsers, add json2.js to shim JSON support in browsers not supporting it natively.
You can use JSON.parse to change the string "[91, 6, 2, 57, 29, 40, 95]" into an array:
​(function(){
var a = '[1,2,3]';
var b = JSON.parse('[1,2,3]');
alert(b +'\n'+ typeof(b)+'\n'+ b[0] );
})()​
Demo
As you are using jQuery you can do
$.parseJSON("[91, 6, 2, 57, 29, 40, 95]");
you can use
str.slice(1, -1).split(',').map(function(s){return parseInt(s, 10);});

Categories