Extracting multi-dimentsional arrays in Javascript/JQuery - javascript

I'm extracting some data from an SQL source, which I can get into a javascript script as a simple array (shown grouped by dates) which consists of week no, task number and hours spent:
mydata = [
// weekno, taskno, hours
["2014-14",160,37.5],
["2014-15",160,30],
["2014-15",243,7.5],
["2014-16",160,37.5],
["2014-17",0,7.5],
["2014-17",3,7.5],
["2014-17",321,22.5],
["2014-18",0,7.5],
["2014-18",321,30],
["2014-19",3,7.5],
["2014-19",295,30]
];
I'm going to be charting it using HighCharts, and I need to get it into two property arrays like this:
properties = {
categories: [ "2014-14","2014-15","2014-16","2014-17","2014-18","2014-19"],
series: [
// Task Week
// No 14 15 16 17 18 19
//
{ name: '0', data: [ 0, 0, 0, 7.5, 7.5, 0 ] },
{ name: '3', data: [ 0, 0, 0, 7.5, 0, 7.5 ] },
{ name: '160', data: [ 37.5, 30, 37.5, 0, 0, 0 ] },
{ name: '243', data: [ 0, 7.5, 0, 0, 0, 0 ] },
{ name: '295', data: [ 0, 0, 0, 0, 0, 30 ] },
{ name: '321', data: [ 0, 0, 0, 22.5, 30, 0 ] }
]
}
Aside from looping, am I missing some succinct, idiomatic method for doing this?

In case it's of use to anyone, here's a cobbled together solution:
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
var categories = [];
var subcategories = [];
var temp = {};
for (var i = 0; i < myChartData.length; i++) {
key = myChartData[i][0];
taskno = myChartData[i][1];
hours = myChartData[i][2];
if (taskno in temp == false) temp[taskno] = {};
if (key in temp[taskno] == false) temp[taskno][key] = 0;
temp[taskno][key] += hours;
categories.push(myChartData[i][0]);
subcategories.push(myChartData[i][1])
}
var uniqueCategories = categories.filter(onlyUnique).sort();
var uniqueSubcategories = subcategories.filter(onlyUnique).sort(function(a, b) {
return a - b
});
var series = [];
for (var i = 0; i < uniqueSubcategories.length; i++) {
subcatKey = uniqueSubcategories[i];
series[i] = { name: 'Task ' + subcatKey, data: [] };
for (var j = 0; j < uniqueCategories.length; j++) {
catKey = uniqueCategories[j];
series[i]['data'].push(temp[subcatKey][catKey] ? temp[subcatKey][catKey] : 0);
}
}
where series and uniqueCategories are the required data.

Related

Sum every last index value with previous values in JS

I have an array:
array = {
"data": [
{ "value": [ 100, 13, 16 ] },
{ "value": [ 101, 14, 17 ] },
{ "value": [ 12, 15, 18 ] }
]
}
Which I am reformatting into a new array of just the columns:
const columnArray = jsonData.map( (current, index, arr) => {
let out = [];
for( let i = 0; i < current.value.length; i++ ) {
out.push( arr[ i ].value[ index ] );
}
return out;
});
// output
[
[ 100, 101, 12 ],
[ 13, 14, 15 ],
[ 16, 17, 18 ]
]
How would I re-write the columnArray mapping to do the column array and be able to sum from the previous value?
So the intended output from the original array would be:
[
[ 100, 201, 213 ],
[ 13, 27, 42 ],
[ 16, 33, 51 ]
]
I would also like the summing to be scalable (though it will always be in a 1:1 ratio). So if the data has 20 items, then each value will have 20 integers in that array too.
I have tried looping through but that didn't work as I only sum from the previous, not all the previous. And this wouldn't scale either:
const columnArray = jsonData.map( (current, index, arr) => {
let out = [];
for( let i = 0; i < current.value.length; i++ ) {
// dont touch first
if( i < 1 ) {
out.push( arr[ i ].value[ index ] );
} else {
out.push( arr[ i ].value[ index ] + arr[ i - 1 ].value[ index ] )
}
}
return out;
});
Instead of pushing the array element, add it to a variable accumulating the running totals, and push that.
const jsonData = [{
"value": [100, 13, 16]
},
{
"value": [101, 14, 17]
},
{
"value": [12, 15, 18]
}
];
const columnArray = jsonData.map((current, index, arr) => {
let out = [];
let total = 0;
for (let i = 0; i < current.value.length; i++) {
total += arr[i].value[index]
out.push(total);
}
return out;
});
console.log(columnArray);
or with a nested map():
const jsonData = [{
"value": [100, 13, 16]
},
{
"value": [101, 14, 17]
},
{
"value": [12, 15, 18]
}
];
const columnArray = jsonData.map((current, index, arr) => {
let total = 0;
return arr.map(el => total += el.value[index])
});
console.log(columnArray);
You're thinking this in the wrong way. You're storing the sum in the list, not anywhere else. So even tho your index is increasing, the resulting sum resides in the list, so to achieve your goal you have to save it in some variable then push the variable into the final list. Follow this code below:
const columnArray = array.data.map((current, index, arr) => {
let out = [];
let temp;
for (let i = 0; i < current.value.length; i++) {
// dont touch first
if (i < 1) {
temp = arr[i].value[index];
out.push(arr[i].value[index]);
} else {
temp = arr[i].value[index] + temp;
out.push(temp);
}
}
return out;
});
something like that...
const array0 = {
"data": [
{ "value": [ 100, 13, 16 ] },
{ "value": [ 101, 14, 17 ] },
{ "value": [ 12, 15, 18 ] }
]
}
const
rowCount = array0.data.reduce((c,{value})=>Math.max(c,value.length) ,0)
, arrResult = Array(rowCount).fill(0).map(x=>Array(array0.data.length).fill(0))
;
arrResult.forEach((_,i,arr)=>
{
array0.data[i].value.forEach((v,j)=>
{
arr[j][i] = v + (i? arr[j][i-1] : 0 )
})
})
console.log( arrResult)
.as-console-wrapper {max-height: 100%!important;top:0}

How to update value in array based on values in another array?

I am having two array like this,
let array1 = [
{
"id": 23,
"name": "Telangana",
}
]
Here i need to update array2 color value inside properties based on array1 numberOfProjects value inside latestMetric. As u can see that in both arrays stateId and id are same.If numberOfProjects value is in the range 1 - 1000. I need to update the color value as 1. then numberOfProjects value is in the range 1000 - 2000. I need to update the color value as 2.so on. I dont know how to achieve this. I tried to map those two arrays and can able to get the ID's.But i dont know how to compare them and update the value . Pleas help me.Thanks in advance
You can do like this
let updatedArr2 = [];
function updateArr2(arr2values, colorValue) {
let updatedProperties = { ...arr2values.properties, color: colorValue };
arr2values.properties = updatedProperties;
updatedArr2.push(arr2values);
}
array2.map(arr2values =>
array1.map(arr1values => {
if (arr2values.properties.stateId === arr1values.latestMetric.stateId) {
if (
arr1values.latestMetric.numberOfProjects >= 1 &&
arr1values.latestMetric.numberOfProjects <= 1000
) {
updateArr2(arr2values, 1);
} else if (
arr2values.latestMetric.numberOfProjects >= 1000 &&
arr2values.latestMetric.numberOfProjects <= 2000
) {
updateArr2(arr2values, 2);
}
}
})
);
console.log(updatedArr2);
You could loop through each object in array1 and then check if there's any object in array2 that matches the stateId, if so, then check the number of projects in the array1 object and change the color of the object in array2 that has the same stateId, something like:
array1.forEach((o) => {
let matches = array2.filter(
(o2) => o2.properties.stateId === o.latestMetric.stateId
);
let projects = o.latestMetric.numberOfProjects;
for (let match of matches) {
if (projects > 1 && projects < 1000) {
match.properties.color = 1;
} else if (projects >= 1000 && projects < 2000) {
match.properties.color = 2;
}
}
});
let array1 = [
{
id: 23,
name: "Telangana",
code: "lnn",
regionId: 1,
isActive: true,
latitude: 17.8495919,
longitude: 79.1151663,
latestMetric: {
stateId: 23,
year: 0,
constructionValueInMn: 84623,
constructionAreaInMnSqft: 32,
numberOfProjects: 406,
noOfCompletedProjects: 19,
noOfOngoingProjects: 387,
noOfUpcomingProjects: 0,
growthRate: 0,
averagePricePerSqftInRs: 0,
totalAreaInMnSqft: 71,
overAllAvgSqft: 0,
eachVariantAvgSqft: 0,
noOfTypeOfVariant: 0,
projectCompletionCycle: 0,
},
createdAt: "2020-04-21T00:35:11.684134",
updatedAt: "2020-04-21T00:35:11.684134",
},
];
let array2 = [
{
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [
[
[77.19721, 28.861519],
[77.203836, 28.86004],
],
],
},
properties: {
cartodb_id: 26,
state_code: 7,
st_nm: "NCT of Delhi",
color: 2,
id: 23,
stateId: 23,
},
},
];
array1.forEach((o) => {
let matches = array2.filter(
(o2) => o2.properties.stateId === o.latestMetric.stateId
);
let projects = o.latestMetric.numberOfProjects;
for (let match of matches) {
if (projects > 1 && projects < 1000) {
match.properties.color = 1;
} else if (projects >= 1000 && projects < 2000) {
match.properties.color = 2;
}
}
});
console.log(array2);
Try this:
array2.map(arr2 => {
//Find to return the position when the id's are the same
const arr1 = array1.find(arr => arr.latestMetric.stateId == arr2.properties.id)
// If find was successful, do this
if (arr1) {
// Destructuring assignment to be easier to compare
const { numberOfProjects } = arr1.latestMetric
if (numberOfProjects >= 1 && numberOfProjects < 1000)
arr2.properties.color = 1
else if (numberOfProjects >= 1000 && numberOfProjects < 2000)
arr2.properties.color = 2
}
})

How to make program to generate json array?

I need to have more destinationColumn to fit in current development environment.
For following example, it shows destinationColumn: 3, 4 and 5.
var columnSummary= [
{
ranges: [[16, 19]],
destinationRow: 20,
destinationColumn: 3,
type: 'sum',
forceNumeric: true
},
{
ranges: [[16, 19]],
destinationRow: 20,
destinationColumn: 4,
type: 'sum',
forceNumeric: true
},
{
ranges: [[16, 19]],
destinationRow: 20,
destinationColumn: 5,
type: 'sum',
forceNumeric: true
}
];
How to make program to generate mentioned array? Any help would be appreciated.
Based on
How to create json by javascript for loop?
donohoe's code
<script>
// var status = document.getElementsByID("uniqueID"); // this works too
var status = document.getElementsByName("status")[0];
var jsonArr = [];
for (var i = 0; i < status.options.length; i++) {
jsonArr.push({
id: status.options[i].text,
optionValue: status.options[i].value
});
}
</script>
I figured out the method to solve my own question, as follows:
var columnSummary = [];
for (var i = 3; i <= 12; i++) {
columnSummary.push({
ranges: [[16, 19]],
destinationRow: 20,
destinationColumn: i,
type: 'sum',
forceNumeric: true
});
}

Change array of object to CSV pattern

i have this following Array :
var objRow = [
{
2011-09-20 : [0, 100, 0],
customerID : C1101,
ANI : 1234
},
{
2011-09-25 : [0, 0, 0],
customerID : C1101,
ANI : 1234
},
{
2011-09-20 : [0, 500, 0],
customerID : C1102,
ANI : 5678
},
{
2011-09-22 : [0, 0, 50],
customerID : C1102,
ANI : 5678
}
]
I want to create CSV Data from array above. But, i have problem to change that array to this CSV pattern :
1234, C1101, 0, 0, 100, 0, 0, 0
5678, C1102, 0, 0, 500, 0, 0, 50
I try to group the customerID using reduce, and because the first index in every object is date. I have some array of dates :
var dateArr = ["2011-09-20", "2011-09-22", "2011-09-25"];
And this is my code :
var result = objRow.reduce(function(prev, curr, index, arr) {
var num = curr["customerID"];
if (!prev[num]) {
prev[num] = [];
}
for (var j = 0; j < dateArr.length; j++) {
prev[num].push(curr[dateArr[j]]);
}
return prev;
}, {});
Update Question
For number combination in date index. I use this rules :
[0, 100, 0] // from first Object
[0, 0, 0] // from second Object
fistObject_firstIndex, secondObject_firstIndex, firstObject_secondIndex, secondObject_secondIndex, firstObject_thirdIndex, secondObject_thirdIndex
0, 0, 100, 0, 0, 0
Up, Down, Up, Down, Up, Down...
How to create CSV Pattern above?
Thank you...
I think this will give you the result you want:
var objRow = [{
date: 2011-09-20,
nums: [0, 100, 0],
customerID: "C1101",
ANI: 1234
}, {
date: 2011-09-25,
nums: [0, 0, 0],
customerID: "C1101",
ANI: 1234
}, {
date: 2011-09-20,
nums: [0, 500, 0],
customerID: "C1102",
ANI: 5678
}, {
date: 2011-09-22,
nums: [0, 0, 50],
customerID: "C1102",
ANI: 5678
}];
//CREATE CSV-FORMATTED STRINGS
var csvLine = "";
var numsArray = new Array();
for (var i=0; i<objRow.length; i++) {
//check if this is the first element with a new 'ANI' (which means a new CSV line starts)
if (objRow[i-1]==(undefined||null) || objRow[i].ANI!=objRow[i-1].ANI) {
//if so, start a new string
csvLine = objRow[i].ANI +", "+ objRow[i].customerID +", "; //add the 'ANI' and 'customerID'
numsArray.length = 0; //clear array
numsArray.push(objRow[i].nums); //store the 'nums' in a separate array
} else {
//if not, add to the existing string
numsArray.push(objRow[i].nums); //store the 'nums' in a separate array
}
//check if this is the last element with the same 'ANI' (which means this CSV line is complete)
if (objRow[i+1]==(undefined||null) || objRow[i].ANI!=objRow[i+1].ANI) {
//add the 'nums' of every object in intertwining order (every 1st, every 2nd, etc.)
for (var k=0; k<numsArray[0].length; k++) {
for (var j=0; j<numsArray.length; j++) {
csvLine += numsArray[j][k].toString() +", ";
}
}
//remove the last comma
if (csvLine.substring(csvLine.length-2) == ", ") {
csvLine = csvLine.substring(0,csvLine.length-2);
}
//output the CSV line
document.getElementById("csv").innerHTML += csvLine + "<br />";
}
}
<div id="csv"></div>
(fiddle: http://jsfiddle.net/5gyp3ce6/16/)
I had to change your array a little bit, because for this to work, the array keys need to all be the same.
Also, I had to change the ID's to strings, otherwise they couldn't be defined.
Instead of writing it to the <div> at the end you can of course add the line to another variable of write it to file or whatever.
If the comments in the code aren't clear enough, just leave a comment and I'll try to explain it better.
Try
var objRow = [
{
"2011-09-20" : [0, 100, 0],
customerID : "C1101",
ANI : 1234
},
{
"2011-09-25" : [0, 0, 0],
customerID : "C1101",
ANI : 1234
},
{
"2011-09-20" : [0, 500, 0],
customerID : "C1102",
ANI : 5678
},
{
"2011-09-22" : [0, 0, 50],
customerID : "C1102",
ANI : 5678
}
];
var arr = [],
res = [],
csv = $.map(objRow, function (v, k) {
// items
arr.push(v.ANI, v.customerID, v[Object.keys(v)[0]]);
// arrays
var a = $.grep(arr, function (val, index) {
return $.isArray(val)
});
// strings
var s = arr.filter(function (i) {
return typeof i === "string"
});
// sort items
res.push([arr.filter(Number)[0]
, s[0]
, a.splice(0, 2).join(",")
, arr.filter(Number).slice(-1)[0]
, s.slice(-1)[0]
, a.join(",")]);
return res
}).slice(-1)[0];
// format text , html
csv = (csv.slice(0, 3) + "<br>" + csv.slice(-3))
.replace(/,/g, ", ");
$("body").append(csv)
var objRow = [
{
"2011-09-20" : [0, 100, 0],
customerID : "C1101",
ANI : 1234
},
{
"2011-09-25" : [0, 0, 0],
customerID : "C1101",
ANI : 1234
},
{
"2011-09-20" : [0, 500, 0],
customerID : "C1102",
ANI : 5678
},
{
"2011-09-22" : [0, 0, 50],
customerID : "C1102",
ANI : 5678
}
];
var arr = [],
res = [],
csv = $.map(objRow, function (v, k) {
arr.push(v.ANI, v.customerID, v[Object.keys(v)[0]]);
// arrays
var a = $.grep(arr, function (val, index) {
return $.isArray(val)
});
// strings
var s = arr.filter(function (i) {
return typeof i === "string"
});
res.push([arr.filter(Number)[0], s[0], a.splice(0, 2).join(","), arr.filter(Number).slice(-1)[0], s.slice(-1)[0], a.join(",")]);
return res
}).slice(-1)[0];
csv = (csv.slice(0, 3) + "<br>" + csv.slice(-3))
.replace(/,/g, ", ");
$("body").append(csv)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Javascript array. Advanced

I have JSON string from my php script like this:
var r.co = {
"A20018425":[
{"balance":"1390.31"}, // 1
{"balance":"1304.11"}, // 2
{"balance":"1188.11"}, // 3
{"balance":"1421.71"} // 4
],
"A25005922":[
{"balance":"1000"}, // 1
{"balance":"1000.86"}, // 2
{"balance":"986.32"}, // 3
{"balance":"988.96"}, // 4
{"balance":"980.26"}, // 5
{"balance":"980.16"} // 6 MAX
],
"A25005923":[
{"balance":"1001"}, // 1
{"balance":"1000.16"}, // 2
]
}
I don't know how many AXXXXXXXX elements and how many elements it contains.
To get A elements I have use the code below:
var accounts = [];
for(var key in r.co) {
if(r.co.hasOwnProperty(key)) {
accounts.push(key);
}
}
Now I know my A elements length
var accounts_length = accounts.length; // 3 for example
Now I need to know max length of elements in A:
var accounts_elements_length = [];
for (var c = 0; c < accounts.length; c++) {
accounts_elements_length.push(r.co[accounts[c]].length);
}
var accounts_elements_length_max = accounts_elements_length.max() // 6 For example
How can I get this output array for the chart?
var outputData = [{
count: 1,
A20018425: 1390.31,
A25005922: 1000,
A25005923: 1001
}, {
count: 2,
A20018425: 1304.11,
A25005922: 1000.86,
A25005923: 1000.16
}, {
count: 3,
A20018425: 1188.11,
A25005922: 986.32
}, {
count: 4,
A20018425: 1421.71,
A25005922: 988.96
}, {
count: 5,
A25005922: 980.26
}, {
count: 6,
A25005922: 980.16
}
}];
Thanks!
Just combined your algorythms:
var outputData = [];
for (var key in r.co) {
if (r.co.hasOwnProperty(key)) {
var account_length = r.co[key].length;
for (var c = 0; c < account_length; c++) {
if (outputData[c] === undefined) {
outputData[c] = { count: c+1 };
}
outputData[c][key] = r.co[key][c].balance;
}
}
}
console.log(outputData);
jsfiddle
Code :
var outputData = [];
for (var i = 0; i < 6; i++) { // filter should be - i < accounts_elements_length_max
var temp = {
'count': i + 1
};
for (var j = 0; j < accounts.length; j++) {
if (r[accounts[j]][i]) temp[accounts[j]] = r[accounts[j]][i].balance;
}
outputData.push(temp);
}
Note that i hard code the accounts_elements_length_max(6).
Output that i get:
[{
"count": 1,
"A20018425": "1390.31",
"A25005922": "1000",
"A25005923": "1001"},
{
"count": 2,
"A20018425": "1304.11",
"A25005922": "1000.86",
"A25005923": "1000.16"},
{
"count": 3,
"A20018425": "1188.11",
"A25005922": "986.32"},
{
"count": 4,
"A20018425": "1421.71",
"A25005922": "988.96"},
{
"count": 5,
"A25005922": "980.26"},
{
"count": 6,
"A25005922": "980.16"}]​
Working fiddle

Categories