Convert JSON data into format in Highcharts' basic line chart - javascript

Using Javascript, I am trying to convert some JSON data into the format used in Highcharts' basic line chart.
What I have to start with:
originalArray = [
['valueA', 1],
['valueA', 0],
['valueB', 9],
['valueB', 9],
['valueB', 3],
['valueC', 11]
]
And what I'm trying to create using the above:
desiredArray = [{
name: 'valueA',
data: [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}, {
name: 'valueB',
data: [0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0]
}, {
name: 'valueC',
data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
}]
For some additional context, the 0-11 in originalArray[i][1] references a month (0 = January), and the desiredArray is a list of unique names and a count of their occurrences by month.
So far, I can:
Convert the data into a new array of objects
For each unique name in originalArray
Create a new object in the desiredArray, and set the name attribute
Add a data attribute that contains an empty array
But then I run into trouble, and can't figure out how to:
Loop through the originalArray
If the name in the originalArray matches the name in the desiredArray
Increment a counter in the matching seriesArray[i].data array, using the value of originalArray[i][1] as the index (it always be 0-11).
So I'm asking:
What's a good way to iterate across my originalArray, match up unique values, and then act only on those matches to push to the desiredArray.
What's the best way to increment the counters in desiredArray[i].data
I'm open to using libraries, such as underscore.js. Have been trying to figure this out for a couple of days now, so pretty much anything goes within the bounds of Javascript.

Updated with proper array initialization, now.
var max = originalArray.reduce(function(p,c){return Math.max(p,c[1]);},0);
var initSums = function(size) {
var arr = new Array(size);
for (var i=0;i<size;i++)
arr[i]=0;
return arr;
}
var map = originalArray.reduce(function(sums,val){
if (!sums.hasOwnProperty(val[0])) {
sums[val[0]] = initSums(max+1);
}
sums[val[0]][val[1]]++;
return sums;
},{});
var desiredArray = Object.keys(map).map(function(key) {
return {name: key, data: map[key]};
});
What we're doing here is a multi-step process:
Decide how big our arrays are going to need to be, by first scanning for the largest value in the original array.
Use an object to aggregate the counts (using Array.reduce()).
Transform the object and its properties into an array of name/data pair objects (using Array.map).

Edit: An improvement on S McCochran's solution, skipping the extraneous search for the maximum value in originalArray, since there should always be 12 elements of each data array, one per month.
function formatForHighcharts(array) {
// Create a map from value name to array of month counts
var map = originalArray.reduce(function(sums, pair) {
var key = pair[0], val = pair[1];
if(!(key in sums))
sums[key] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
// val is the month index, which corresponds directly to array index, so increase that
sums[key][val]++;
return sums;
}, {});
// Map the object to an array of { name: ..., data: ... } pairs
var formatted = Object.keys(map).map(function (key) {
return { name: key, data: map[key] };
});
return formatted;
}
Usage:
var desiredArray = formatForHighcharts(originalArray);

Related

Add item to specific position otherwise push zero in array in javascript

I have empty array in that I want to add specific items at specific position which are coming from web api and want to add zero(0) to remaining positions dynamically using javscript.
Here is my Code :-
let arraydata = [0, 0, 0, 0, 0,0,0,0,0,0,0,0]
arraydata.splice(5, 0, 4)
document.querySelector("#app").innerHTML = arraydata;
My Code
Right now I have added zero manually,I want to add 0 upto 12 index and want to add 4 at 5th position synamicaaly.
Use map:
let arraydata = Array(12).fill();
arraydata.splice(5, 0, 4);
arraydata = arraydata.map(e => e ? e : 0);
console.log(arraydata);
You can also add different values - just place them inside the fill:
let arraydata = Array(12).fill("Things");
arraydata.splice(5, 0, 4);
arraydata = arraydata.map(e => e ? e : 0);
console.log(arraydata);
You can fill() array with 0
let arraydata = Array(12).fill(0)
arraydata.splice(5, 0, 4)
console.log(arraydata)
Use Array.fill
let array = new Array(12).fill(0);
array.splice(5,0,4);
console.log(array);
If you want to update an index rather than adding a new value at particular index, rather than splice, you should simply do array[5] = 4
You can build a generic function like this
let desiredArr = (length, value, from, to)=>{
let arr = new Array(length).fill(0)
arr.splice(value, from, to)
return arr
}
console.log(desiredArr(12, 5, 0 ,4))
If there's always only one index you want to update than you can simply do this
let arr = new Array(12).fill(0)
arr[5] = 4
console.log(arr)
You could just assign the value at the wanted index without splicing, which increases the length of the array.
let arraydata = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
arraydata[5] = 4;
console.log(...arraydata);
If you like to keep the splicing, you could keep the length by assigning the wwanted length.
let arraydata = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
arraydata.splice(5, 0, 4);
arraydata.length = 12;
console.log(...arraydata);

Object with 8 different value sets

Hello everyone i'm trying to make an object that will show a different set of values based off the index chosen.
<script>
var schedule = {
max_schedule: 8, // number of schedules
for (i = 0; i < max_schedule; i++){
value1[i]: [0, 0, 0],
value2[i]: [0, 0, 0],
value3[i]: "",
value4[i]: "",
value5[i]: 0,
value6[i]: 0,
value7[i]: 0,
value8[i]: 0,
value9[i]: false
}
};
</script>
I am unsure how to do this as trying to create an object while using a for-loop seems to lead to syntactical errors
Thank you for any help.
Maybe you are looking for something like this?
var schedule = {
max_schedule: 8, // number of schedules
};
for (i = 0; i < schedule.max_schedule; i++){
schedule['value1'+i]= [0, 0, 0],
schedule['value2'+i]= [0, 0, 0],
schedule['value3'+i]= "",
schedule['value4'+i]= "",
schedule['value5'+i]= 0,
schedule['value6'+i]= 0,
schedule['value7'+i]= 0,
schedule['value8'+i]= 0,
schedule['value9'+i]= false
}
console.log(schedule)
JS objects do not work like that. Do some further research, is pretty important to know how objects work since they are an essential part of JavaScript.
About your issue, i think this is what you are trying to do. I guess you receive those values from a database and then you want to set a number of schedules and create the object based on that number.
Check this
var values = [[0, 0, 0], [0, 0, 0], "", "", 0, 0, 0, 0, false];
var schedule = {};
var max_schedule = 8;
for(var index = 0; index < max_schedule; index++) {
schedule['value' + index] = values[index];
}
console.log(schedule);

JS, difference in array matrix and forEach behavior

I was doing some training tasks for my JS course and I got one where you must implement a function that takes a positive integer (n) and returns a matrix like the one below (5 was passed):
[ [ 1, 0, 0, 0, 0 ],
[ 0, 1, 0, 0, 0 ],
[ 0, 0, 1, 0, 0 ],
[ 0, 0, 0, 1, 0 ],
[ 0, 0, 0, 0, 1 ] ]
I was able to implement the function with the following code:
function getIdentityMatrix(n) {
const mat = new Array(n).fill([]);
return mat.map((row, index) => {
row = new Array(n).fill(0);
row[index] = 1;
return row;
});
}
But while doing it I found a strange behavior that I can't explain... If I alter the code a little:
function getIdentityMatrix(n) {
const mat = new Array(n).fill(new Array(n).fill(0));
return mat.map((row, index) => {
row[index] = 1;
return row;
});
}
It returns a matrix like this:
[ [ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ] ]
Why would it work that way? It's like the forEach function iterates over all the elements nested inside each row which it shouldn't do.
Thank you for any advise!
It's because Array is a reference type. When you do
new Array(n).fill(new Array(n).fill(0))
first the inner new Array(n).fill(0) makes an array size n filled with 0; next the outer Array(n).fill creates an array filled with n references to that inner array.
It doesn't create n inner arrays, just n references to the same array. So when you change an element of that inner array, all the references in the outer array will reflect the change since they all point to the same object.
The code in question is equivalent to this:
let n = 5
let innerArr = new Array(n).fill(0)
function getIdentityMatrix(n) {
const mat = new Array(n).fill(innerArr);
return mat.map((row, index) => {
row[index] = 1;
return row;
});
}
console.log(getIdentityMatrix(n))
Because you are using fill you are basically filling that mat array with references to the innerArr (which you can see clearly from the above console output).
Then you do row[index] = 1 for each i which is changing the same values (at i index) of the same array.
Now your working example ... which could be written in a shorter form as:
const getIdentityMatrix = (n) =>
[...Array(n)].map((row, index) => {
row = Array(n).fill(0)
row[index] = 1
return row
})
console.log(getIdentityMatrix(3))
Clearly maps over a newly created and then spreaded array of n but then overwrites each element with an entirely new array reference.
Since that reference is brand new modifying it with row[index] = 1 produces the expected behavior when we return the x from the map.
Another way to achieve this in one line is via map, Object.assign and Object.values like this:
const gm = (n) => [...Array(n)].map((x,i) =>
Object.values(Object.assign(Object.assign({}, Array(n).fill(0)), {[i]:1})))
console.log(gm(3))
// your example is roughly equivalent to this.
const innerArray = new Array(n).fill(0);
const mat = new Array(n).fill(innerArray);
(mat[0] === mat[1] === innerArray) === true;
there is only 1 nested array, not n times array.

Array splitting based on value

How could I split an array by value like this:
[0, 1, 2, 0, 0, 0, 1, 0] =>
[[0, 1, 2], [0], [0], [0, 1], [0]]?
I'm using lodash documentary, but kinda out of ideas for now. Is there any way to do this with _.groupBy?
Thanks for your answers.
Use native JavaScrip Array#reduce method.
var data = [0, 1, 2, 0, 0, 0, 1, 0],
last;
var res = data.reduce(function(arr, v) {
// check the difference between last value and current
// value is 1
if (v - last == 1)
// if 1 then push the value into the last array element
arr[arr.length - 1].push(v)
else
// else push it as a new array element
arr.push([v]);
// update the last element value
last = v;
// return the array refernece
return arr;
// set initial value as empty array
}, [])
console.log(res);
Below is succinct solution in ES2015 (formerly ES6).
const newArray = [];
[0, 1, 2, 0, 0, 0, 1, 0].forEach(item => item === 0 ?
newArray.push([0]) :
newArray[newArray.length - 1].push(item)
);
console.log(newArray);
If you have to start a new array when you encounter a zero you can resort to
this code, hope it is not appear as vodoo programming.
var x = [0, 1, 2, 0, 0, 0, 1, 0];
x.join("") /* convert the array to a string */
.match(/(0[^0]*)/g) /* use a regex to split the string
into sequences starting with a zero
and running until you encounter
another zero */
.map(x=>x.split("")) /* get back the array splitting the
string chars one by one */
I assume that the array elements are just a digit long and that 0 is the start of every sub array.
Removing the one digit assumption would resort to this code:
var x = [0, 1, 2, 0, 12, 0, 0, 1, 0];
var the_regexp = /0(,[1-9]\d*)*/g;
x.join(",") /* convert the array to a comma separated
string */
.match(the_regexp) /* this regex is slightly different from
the previous one (see the note) */
.map(x=>x.split(",")) /* recreate the array */
In this solution we separate the array elements with a comma, Let's examine the regEx:
/0 means that every sub array starts with a 0, / is the beginning of the match
,[1-9]\d* this sub pattern match an the integer if it has a comma in front; the first digit cannot be 0, the other, optional, digits do not have this limitation. Thus we match ,1 or ,200 or ,9 or ,549302387439209.
We have to include in the subarray all the consecutive non zero number we find (,[1-9]\d*)* maybe none hence the second *.
`/g' closes the RegExp. The g indicates we want all the matches and not just the first one.
If you prefer an oneliner:
x.join(",").match(/0(,[1-9]\d*)*/g).map(x=>x.split(','));
or, if you prefer the pre ECMA2015 function expression syntax:
x.join(",").match(/0(,[1-9]\d*)*/g).map(function(x){return x.split(',');});
You could use a new array for every found zero value, otherwise append to the last array in the result set.
var array = [0, 1, 2, 0, 0, 0, 1, 0],
result = array.reduce(function (r, a) {
if (a) {
r[r.length - 1].push(a);
} else {
r.push([a]);
}
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Javascript array with objects

I want to create/instantiate an array objectArray with several objects, whereby the objects shall contain x and y (empty at the beginning).
The length (amount of objects) of objectArray needs to be the same as the length of i.e. arrayLong. How I have to implement that?
Finally, it should look like that (etc. corresponding to the length of arrayLong):
var objectArray = [ { x: 0, y: 0 }, { x: 0, y: 0 }, { x: 0, y: 0 } etc. ];
Simple:
var objectArray = []; // Declare the array variable
for(var i = 0; i < arrayLong; i++){ // Do something `arrayLong` times
objectArray.push({x: 0, y:0}); // Add a object to the array.
}
This assumes arrayLong is a numeric value, of course.
Another way you could do it, is this:
var objectArray = Array.apply(null, Array(arrayLong))
.map(function(){return {x: 0, y:0}});

Categories

Resources