JSON data transformation from table-like format to JSON? - javascript

I have data that's in this format:
{
"columns": [
{
"values": [
{
"data": [
"Project Name",
"Owner",
"Creation Date",
"Completed Tasks"
]
}
]
}
],
"rows": [
{
"values": [
{
"data": [
"My Project 1",
"Franklin",
"7/1/2015",
"387"
]
}
]
},
{
"values": [
{
"data": [
"My Project 2",
"Beth",
"7/12/2015",
"402"
]
}
]
}
]
}
Is there some super short/easy way I can format it like so:
{
"projects": [
{
"projectName": "My Project 1",
"owner": "Franklin",
"creationDate": "7/1/2015",
"completedTasks": "387"
},
{
"projectName": "My Project 2",
"owner": "Beth",
"creationDate": "7/12/2015",
"completedTasks": "402"
}
]
}
I've already got the column name translation code:
r = s.replace(/\%/g, 'Perc')
.replace(/^[0-9A-Z]/g, function (x) {
return x.toLowerCase();
}).replace(/[\(\)\s]/g, '');
Before I dive into this with a bunch of forEach loops, I was wondering if there was a super quick way to transform this. I'm open to using libraries such as Underscore.

function translate(str) {
return str.replace(/\%/g, 'Perc')
.replace(/^[0-9A-Z]/g, function (x) {
return x.toLowerCase();
})
.replace(/[\(\)\s]/g, '');
}
function newFormat(obj) {
// grab the column names
var colNames = obj.columns[0].values[0].data;
// create a new temporary array
var out = [];
var rows = obj.rows;
// loop over the rows
rows.forEach(function (row) {
var record = row.values[0].data;
// create a new object, loop over the existing array elements
// and add them to the object using the column names as keys
var newRec = {};
for (var i = 0, l = record.length; i < l; i++) {
newRec[translate(colNames[i])] = record[i];
}
// push the new object to the array
out.push(newRec);
});
// return the final object
return { projects: out };
}
DEMO

There is no easy way, and this is really not that complex of an operation, even using for loops. I don't know why you would want to use regex to do this.
I would start with reading out the column values into a numerically indexed array.
So something like:
var sourceData = JSON.parse(yourJSONstring);
var columns = sourceData.columns[0].values[0].data;
Now you have a convenient way to start building your desired object. You can use the columns array created above to provide property key labels in your final object.
var sourceRows = sourceData.rows;
var finalData = {
"projects": []
};
// iterate through rows and write to object
for (i = 0; i < sourceRows.length; i++) {
var sourceRow = sourceRows[i].values.data;
// load data from row in finalData object
for (j = 0; j < sourceRow.length; j++) {
finalData.projects[i][columns[j]] = sourceRow[j];
}
}
That should do the trick for you.

Related

Ask for help on how to get all the filtered list from specific array

I have an object in an array called "Person".
Within the object "Person", there is an array called "info".
My goal is to get all the values with the prefix "age:" in an array "info" when filtering by "gender:male". So, my desired output will be 1 to 9 because I want also to remove duplicates.
Below is my code but the results are only two values (1 and 4). Maybe the output is one value per person.
I spent a lot of hours playing the code but no luck. That's why I bring my problem here hoping anybody who is an expert on this can help me.
<script>
var array = [
{
"person": {
"info": [
"age:1",
"age:2",
"age:3",
"age:4",
"age:5",
"age:6",
"gender:male"
]
},
"person": {
"info": [
"age:4",
"age:5",
"age:6",
"age:7",
"age:8",
"age:9",
"gender:male"
]
},
"person": {
"info": [
"age:8",
"age:9",
"age:10",
"age:11",
"age:12",
"age:13",
"gender:female"
]
}
}
]
var filteredAges = [];
for (i = 0; i < array.length; i++) {
var infoGroup = array[i].person.info,
ageGroup = [];
for (j = 0; j < infoGroup.length; j++) {
ageGroup.push(infoGroup[j]);
var ageInfo = ageGroup.find(ages => ages.includes('age:'));
};
if (ageInfo) {
if (filteredAges.indexOf(ageInfo) == -1) {
filteredAges.push(ageInfo)
}
}
}
for (i = 0;i < filteredAges.length; i++) {
console.log(filteredAges[i]);
}
</script>
Seems like all your object keys are just person i.e
[
{
person: {...},
person: {...},
person: {...}
}
]
So when the variable array is evaluated it just has one person
You need to restructure your data maybe like below or something similar
Example - 1
[
{ person: {...} },
{ person: {...} },
{ person: {...} },
]
Example - 2
[
[ { person: {...} } ],
[ { person: {...} } ],
[ { person: {...} } ]
]
After fixing this you can try debugging your problem
If you want to get all items in info array that has "age:"
you can use filter like this
const ageInfos = [
"age:8", "age:9",
"age:10", "age:11",
"age:12", "age:13",
"gender:female"
].filter(x => x.startsWith("age:"))
Your output - ageInfos will be
["age:8", "age:9", "age:10", "age:11", "age:12", "age:13"]
You can also use Set to only collect unique strings or just push everything to an array and later use Set to return only unique values like this
const arrayWithDuplicates = ['a', 1, 'a', 2, '1'];
const unique = [...new Set(arrayWithDuplicates)];
console.log(unique); // unique is ['a', 1, 2, '1']
First of all, your JSON is wrong. You just overright person object.
Data structure is really awful, I would recommend you to rethink it.
Assuming person will not be overwritten I came up with this solution.
var array = [
{
"person": {
"info": [
"age:1",
"age:2",
"age:3",
"age:4",
"age:5",
"age:6",
"gender:male"
]
},
"person1": {
"info": [
"age:4",
"age:5",
"age:6",
"age:7",
"age:8",
"age:9",
"gender:male"
]
},
"person2": {
"info": [
"age:8",
"age:9",
"age:10",
"age:11",
"age:12",
"age:13",
"gender:female"
]
}
}
]
let agesArray = []
let ages = []
array.forEach((peopleObj) => {
for (const index in peopleObj) {
ages = peopleObj[index].info.map((age) => {
const ageNumber = age.split(':')[1]
if (parseInt(ageNumber)) {
return ageNumber
}
}).filter(val => !!val)
agesArray = [...agesArray, ...ages]
}
})
Thanks a lot guys. I'll apply all of your ideas and try if it can solve my problem.

Issue while converting array from one format to another

I have the following input array(It's a Javascript Object[] Array response):
[
{index:1, headerCSV:"Name", dataFields: ["Name", "Id"]},
{index:2, headerCSV:"Id", dataFields: ["Test", "Test 1"]},
{index:3, headerCSV:"fname", dataFields: ["Test", "Test 1"]},
{index:4, headerCSV:"lname", dataFields: []},
]
I am trying to convert it to the following array:
[
{"header" : 1, "field" :"Name"},
{"header" : 1, "field" :"Id"},
{"header" : 2, "field" :"Test"},
{"header" : 2, "field" :"Test 1"},
{"header" : 3, "field" :"Test"},
{"header" : 3, "field" :"Test 1"}
]
In the result array I'll need to put in the header with the input array index and in the field I'll need to construct using the array of the dataFields array of the input array. I have tried with the following code:
var CSVHeadersAndFields = /* The input array */;
var headerFieldMappingJSON = [];
for(var i=0; i<CSVHeadersAndFields.length;i++) {
headerFieldMappingJSON[i] = {};
var selectedFields = CSVHeadersAndFields[i].dataFields;
for(var j=0; j<selectedFields.length;j++) {
headerFieldMappingJSON[i].header = CSVHeadersAndFields[i].index;
headerFieldMappingJSON[i].field = selectedFields[j];
}
}
But I have got the following result:
[
{"header":1,"field":"Name"},
{"header":2,"field":"Test"},
{"header":3,"field":"Test"},
{}
]
I suspect form the for loop 1st iteration value is replaced by the second iteration and also I'll need to avoid to construct the output array mapping from the empty array of dataFields from the input array.
How to make a correct algorithm to convert the array?
Make a separate iterator index for the result array. Or just push to the result array instead of adding values by index:
var CSVHeadersAndFields = /* The array from question */;
var headerFieldMappingJSON = [];
for(var i = 0; i < CSVHeadersAndFields.length; i++) {
var selectedFields = CSVHeadersAndFields[i].dataFields;
for(var j = 0; j < selectedFields.length; j++) {
headerFieldMappingJSON.push({
header: CSVHeadersAndFields[i].index,
field: selectedFields[j]
});
}
}
The same example but cleaner:
var input = /* The array from question */;
var output = [];
input.forEach(function (csvRow) {
csvRow.dataFields.forEach(function (field) {
output.push({
header: csvRow.index,
field: field
});
});
});
You can try following approach:
Logic:
Loop over data and push data in an array based on parsing logic.
In every iteration, you can again loop over obj.dataFields and create object for every field.
You can then merge this output array to original output list.
var data = [
{index:1, headerCSV:"Name", dataFields: ["Name", "Id"] },
{index:2, headerCSV:"Id", dataFields: ["Test", "Test 1"] },
{index:3, headerCSV:"fname", dataFields: ["Test", "Test 1"] },
{index:4, headerCSV:"lname", dataFields: []}
];
var output = data.reduce((acc, obj) => {
const header = obj.index;
return acc.concat( obj.dataFields.map((field) => ({ header, field}) ))
}, []);
console.log(output)
The code below will give you one result object per dataField and use the index property from CSVHeadersAndFields as the header property for each of them.
const result = CSVHeadersAndFields.map(item =>
item.dataFields.map(field => {
return {
header: item.index,
field
}
})
);
here is the simpler code:
var CSVHeadersAndFields = [ {index:1, headerCSV:"Name", dataFields: ["Name","Id"]},
{index:2, headerCSV:"Id", dataFields:["Test","Test 1"]},{index:3, headerCSV:"fname", dataFields:["Test","Test 1"]}, {index:4, headerCSV:"lname", dataFields:[]};
var headerFieldMappingJSON = [];
for(var CSVHeadersAndField of CSVHeadersAndFields ) {
for(var dataFieldVal of CSVHeadersAndField['dataFields']){
headerFieldMappingJSON.push({'header': CSVHeadersAndField['index'], 'field': dataFieldVal })
}
}
output:
[
{
"header": 1,
"field": "Name"
},
{
"header": 1,
"field": "Id"
},
{
"header": 2,
"field": "Test"
},
{
"header": 2,
"field": "Test 1"
},
{
"header": 3,
"field": "Test"
},
{
"header": 3,
"field": "Test 1"
}
]

How to add a new key to multiple indices of an array of objects?

I've got an array of three people. I want to add a new key to multiple objects at once based on an array of indices. Clearly my attempt at using multiple indices doesn't work but I can't seem to find the correct approach.
var array = [
{
"name": "Tom",
},
{
"name": "Dick",
},
{
"name": "Harry",
}
];
array[0,1].title = "Manager";
array[2].title = "Staff";
console.log(array);
Which returns this:
[
{
"name": "Tom",
},
{
"name": "Dick",
"title": "Manager"
},
{
"name": "Harry",
"title": "Staff"
}
]
But I'd like it to return this.
[
{
"name": "Tom",
"title": "Manager"
},
{
"name": "Dick",
"title": "Manager"
},
{
"name": "Harry",
"title": "Staff"
}
]
You cannot use multiple keys by using any separator in arrays.
Wrong: array[x, y]
Correct: array[x] and array[y]
In your case, it will be array[0].title = array[1].title = "manager";
1st method::
array[0].title = "Manager";
array[1].title = "Manager";
array[2].title = "Staff";
array[0,1] will not work.
2nd method::
for(var i=0;i<array.length;i++) {
var msg = "Manager";
if(i===2) {
msg = "Staff"
}
array[i].title = msg
}
You can use a helper function like this
function setMultiple(array, key, indexes, value)
{
for(i in array.length)
{
if(indexes.indexOf(i)>=0){
array[i][key] = value;
}
}
}
And then
setMultiple(array, "title", [0,1], "Manager");
Try this: `
for (var i=0; var<= array.length; i++){
array[i].title = "manager";
}`
Or you can change it around so var is less than or equal to any n range of keys in the index.
EDIT: instead make var <= 1. The point is to make for loops for the range of indices you want to change the title to.
Assuming that you have a bigger set of array objects.
var array = [
{
"name": "Tom",
},
{
"name": "Dick",
},
{
"name": "Harry",
},
.
.
.
];
Create an object for the new keys you want to add like so:
let newKeys = {
'Manager': [0,2],
'Staff': [1]
}
Now you can add more such titles here with the required indexes.
with that, you can do something like:
function addCustomProperty(array, newKeys, newProp) {
for (let key in newKeys) {
array.forEach((el, index) => {
if (key.indexOf(index) > -1) { // if the array corresponding to
el[newProp] = key // the key has the current array object
} // index, then add the key to the
}) // object.
}
return array
}
let someVar = addCustomProperty(array, newKeys, 'title')

Ordering recursive function results in arrays of arrays

I am currently dealing with in issue in writing a recrusive function to order some json data. I have several nested arrays of objects which i need to order into single slides. The structure is similar to the following :
[
{
"title": "a",
"children": [
{
"title": "a-a",
"children": [
{
"title": "a-a-a"
},
{
"title": "a-a-b"
}
]
},
{
"title": "a-b",
"children": [
{
"title": "a-b-a"
},
{
"title": "a-b-b"
}
]
}
]
},
{
"title": "b",
"children": [
{
"title": "b-a",
"children": [
{
"title": "b-a-a"
},
{
"title": "b-a-b"
}
]
},
{
"title": "b-b",
"children": [
{
"title": "b-b-a"
},
{
"title": "b-b-b"
}
]
}
]
}
]
I have written a recursive function :
var catalog = {
init: function() {
var _this = this;
$.getJSON("catalog.json", function(data) {
_this.slides = [];
_this.parseCategories(data.catalog.category,-1,0);
});
},
parseCategories: function(array, depth, prevParent) {
++depth;
if (!this.slides[depth]) this.slides[depth] = [];
if (!this.slides[depth][prevParent]) this.slides[depth][prevParent] = [];
this.slides[depth][prevParent].push(array);
for (var i = 0; i < array.length; i++) {
if (array[i].category) {
this.parseCategories(array[i].category, depth, i);
}
}
}
}
catalog.init();
This outputs :
However instead of retrieving the data for my third slide under format :
a-a-a
a-b-a
a-c-a
I would like to get
a-a-[a,b,c]
I was wondering if that was possible since I'm not very good at handling recursive processes. I hope I was clear and thank you for reading this.
I basically need to keep my original data structure but remove the first depth level for each iteration (slide in a slider that represent increasing depths in my data structure).
I recently wrote a algorithm to recursively handle data like this. Here is a jsfiddle and the main function
console.log('starting');
// data in tree format.
var output = {};
// data in slide format ["a-a-a", "a-a-b", "b-b-a", "b-b-b"]
var outputStrs = [];
parseData(data, output);
console.log(output);
console.log(outputStrs);
function parseData(data, store) {
// go through each element
for (var i = 0; i < data.length; i++) {
var element = data[i];
// used to keep track of where we are in the tree.
var splitElement = element.title.split('-');
var titleStart = splitElement[0];
// console.log(element);
if (_.has(element, 'children') && _.isArray(element.children)) {
// if there is a children, then recursively handle it.
store[titleStart] = {};
parseData(element.children, store[titleStart]);
} else {
// if we are at the end, then add in the data differently.
var titleEnd = splitElement[splitElement.length-1];
store[titleEnd] = titleEnd;
// create the slides
var slide = [];
for (var j = 0; j < splitElement.length; j++) {
if (j !== splitElement.length - 1) {
slide.push(titleStart);
} else {
slide.push(titleEnd);
}
}
slide = slide.join('-');
if (!_.contains(outputStrs, slide)) outputStrs.push(slide);
}
}
}
With this data the output should resemble
a
a
a
b
b
b
a
b
And outputStrs will resemble a-a-[a,b,c]
Hope this helps!!!

complex grouping and merging array as properties

I wish to put an array into other's array as proproties by matching their common properties. I want jobDetails's uId to match with job's uId. Possible?
var job = [{
"uId": 1
}, {
"uId": 2
}]
var jobDetails = [{
"uId": 1,
"salary": 5000
}, {
"uId": 2,
"salary": 5000
}]
is it possible to produce something like
var job = [{
"uId": 1,
"salary": [{
"uId": 1,
"salary": 5000
}]
}, {
"uId": 2,
"salary": [{
"uId": 2,
"salary": 5000
}]
}];
You may try something like this: http://jqversion.com/#!/XWFtbQb
for (var i = 0; i < job.length; i++) {
for (var j = 0; j < jobDetails.length; j++) {
if (job[i].uId == jobDetails[j].uId) {
job[i].salary = jobDetails[j];
}
}
}
console.log(job);
This is not a pure javascript solution, but I like to use underscore.js for this kind of typical actions on collections:
http://jsfiddle.net/FPwq7/
var finalCollection = [];
_.each(job, function(model){
var obj = _.findWhere(jobDetails, {uId: model.uId});
_.extend(model, {'salaray': obj});
finalCollection.push(model);
});
console.log(finalCollection);
I found that this Javascript utility belt takes care of some heavy lifting, and it makes the code a bit more pleasant to read than reading dry loops.
Yes possible , you need to play with both json objects
var array = [];
var object = {}
$.each( job, function ( k , kal ) {
$.each( jobDetails , function ( i , val) {
object.uId = i;
object.salary = val;
});
array.push(object);
});
console.log(JSON.stringify(array));

Categories