I have this simple JSON array structure
[
[ "1000", "Kangar","Perlis" ],
[ "1532", "Kangar", "Perlis" ],
[ "2000", "Kuala Perlis", "Perlis" ],
[ "6250", "Alor Setar", "Kedah" ],
[ "6300", "Kuala Nerang", "Kedah" ]
]
Now i want to structure the JSON like this
{
"Perlis":
{
"Kangar": [ "1000", "1532" ],
"Kuala Perlis": [ "2000" ]
},
"Kedah":
{
"Alor Setar":["6250"],
"Kuala Nerang":["2000"]
}
}
So how can i achieve this result using Javascript's object?
Try following
var arr = [
["1000", "Kangar", "Perlis"],
["1532", "Kangar", "Perlis"],
["2000", "Kuala Perlis", "Perlis"],
["6250", "Alor Setar", "Kedah"],
["6300", "Kuala Nerang", "Kedah"]
];
var obj = {};
arr.forEach(function(item) {
obj[item[2]] = obj[item[2]] || {};
obj[item[2]][item[1]] = obj[item[2]][item[1]] || [];
obj[item[2]][item[1]].push(item[0]);
});
console.log(obj);
You can use reduce to create the hash object like this:
function transform(arr) {
return arr.reduce(function(hash, sub) {
if(hash [sub[2]]) { // if we hashed the first-level-categry (sub[2])
if(hash [sub[2]] [sub[1]]) // -- if we hashed the second-level category (sub[1])
hash [sub[2]] [sub[1]].push(sub[0]); // ---- add the item (sub[0]) to that array
else // -- otherwise
hash [sub[2]] [sub[1]] = [sub[0]]; // ---- create second-level-category placeholder (new array) that initially contains the current item (sub[0])
}
else { // else
hash [sub[2]] = {}; // -- create the first-level-category placeholder
hash [sub[2]] [sub[1]] = [sub[0]]; // -- create the second-level-category placeholder (new array) that initially contains the current item (sub[0])
}
return hash;
}, {});
}
var array = [
["1000","Kangar","Perlis"],
["1532","Kangar","Perlis"],
["2000","Kuala Perlis","Perlis"],
["6250","Alor Setar","Kedah"],
["6300","Kuala Nerang","Kedah"]
];
console.log(transform(array));
var inputArr = [
["1000","Kangar","Perlis"],
["1532","Kangar","Perlis"],
["2000","Kuala Perlis","Perlis"],
["6250","Alor Setar","Kedah"],
["6300","Kuala Nerang","Kedah"]
];
var processFunction = function(arr){
var outputObj = {};
arr.forEach( function(elem){
if( !outputObj[ elem[2] ] )
outputObj[ elem[2] ] ={};
if( !outputObj[ elem[2] ] [ elem[1] ])
outputObj[ elem[2] ][ elem[1] ] = [];
outputObj[ elem[2] ][ elem[1] ].push( elem[0] );
});
return outputObj;
};
alert(JSON.stringify(processFunction(inputArr)) );
var arr = [
["1000", "Kangar", "Perlis"],
["1532", "Kangar", "Perlis"],
["2000", "Kuala Perlis", "Perlis"],
["6250", "Alor Setar", "Kedah"],
["6300", "Kuala Nerang", "Kedah"]
]
function convert(arr) {
return arr.reduce(function (o, e) {
o[e[2]] = o[e[2]] || {};
o[e[2]][e[1]] = o[e[2]][e[1]] || [];
o[e[2]][e[1]].push(e[0]);
return o;
}, {});
}
console.log(convert(arr));
What this o[e[2]] = o[e[2]] || {} does is it sets o[e[2]] to itself, or if it's a falsy value (like undefined) - to a new object. This acts as an easy initialization and prevents accessing non-existent values.
To be safe, you can add a check for each array element's length:
return arr.reduce(function(o, e) {
if (e.length === 3) {
...
}
return o;
}, {});
You can do this with reduce().
var data = [
["1000", "Kangar", "Perlis"],
["1532", "Kangar", "Perlis"],
["2000", "Kuala Perlis", "Perlis"],
["6250", "Alor Setar", "Kedah"],
["6300", "Kuala Nerang", "Kedah"]
]
var o = {}
var result = data.reduce(function(r, e) {
if (!o[e[1]]) {
o[e[1]] = {[e[1]]: []}
r[e[2]] = Object.assign((r[e[2]] || {}), o[e[1]])
}
o[e[1]][e[1]].push(e[0])
return r
}, {})
console.log(result)
Related
I have a Json data that I want to have in a different format.
My original json data is:
{
"info": {
"file1": {
"book1": {
"lines": {
"102:0": [
"102:0"
],
"105:4": [
"106:4"
],
"106:4": [
"107:1",
"108:1"
]
}
}
}
}
}
And I want to map it as following:
{
"name": "main",
"children": [
{
"name": "file1",
"children": [
{
"name": "book1",
"group": "1",
"lines": [
"102",
"102"
],
[
"105",
"106"
],
[
"106",
"107",
"108"
]
}
],
"group": 1,
}
],
"group": 0
}
But the number of books and number of files will be more. Here in the lines the 1st part (before the :) inside the "" is taken ("106:4" becomes "106"). The number from the key goes 1st and then the number(s) from the value goes and make a list (["106", "107", "108"]). The group information is new and it depends on parent-child information. 1st parent is group 0 and so on. The first name ("main") is also user defined.
I tried the following code so far:
function build(data) {
return Object.entries(data).reduce((r, [key, value], idx) => {
//const obj = {}
const obj = {
name: 'main',
children: [],
group: 0,
lines: []
}
if (key !== 'reduced control flow') {
obj.name = key;
obj.children = build(value)
if(!(key.includes(":")))
obj.group = idx + 1;
} else {
if (!obj.lines) obj.lines = [];
Object.entries(value).forEach(([k, v]) => {
obj.lines.push([k, ...v].map(e => e.split(':').shift()))
})
}
r.push(obj)
return r;
}, [])
}
const result = build(data);
console.log(result);
The group information is not generating correctly. I am trying to figure out that how to get the correct group information. I would really appreciate if you can help me to figure it out.
You could use reduce method and create recursive function to build the nested structure.
const data = {"info":{"file1":{"book1":{"lines":{"102:0":["102:0"],"105:4":["106:4"],"106:4":["107:1","108:1"]}}}}}
function build(data) {
return Object.entries(data).reduce((r, [key, value]) => {
const obj = {}
if (key !== 'lines') {
obj.name = key;
obj.children = build(value)
} else {
if (!obj.lines) obj.lines = [];
Object.entries(value).forEach(([k, v]) => {
obj.lines.push([k, ...v].map(e => e.split(':').shift()))
})
}
r.push(obj)
return r;
}, [])
}
const result = build(data);
console.log(result);
I couldn't understand the logic behind group property, so you might need to add more info for that, but for the rest, you can try these 2 functions that recursively transform the object into what you are trying to get.
var a = {"info":{"file1":{"book1":{"lines":{"102:0":["102:0"],"105:4":["106:4"],"106:4":["107:1","108:1"]}}}}};
var transform = function (o) {
return Object.keys(o)
.map((k) => {
return {"name": k, "children": (k === "lines" ? parseLines(o[k]) : transform(o[k])) }
}
)
}
var parseLines = function (lines) {
return Object.keys(lines)
.map(v => [v.split(':')[0], ...(lines[v].map(l => l.split(":")[0]))])
}
console.log(JSON.stringify(transform(a)[0], null, 2));
I have a data object like this :
{
"data1": [
[
"ID",
"name",
"Birthday"
],
[
"10",
"thomas",
"1992-03-17"
],
[
"11",
"Emily",
"2000-03-03"
]
],
"data2": [
[
"Balance",
"ID"
],
[
"$4500",
"10"
],
[
"$1500",
"13"
]
]
}
It contains two arrays data1 and data2.
The first row in each array is the name of the columns and the rest of the rows have the data (think of it like a table).
I want to compare the ID field in both arrays and if the IDs match then the final output will contain a column Balance with the balance corresponding to that ID and if the IDs don't match then the Balance will be $0.
Expected output:
{
"output": [
[
"ID",
"name",
"Birthday",
"Balance"
],
[
"10",
"thomas",
"1992-03-17",
"$4500" //ID 10 matched so the balance added here
],
[
"11",
"Emily",
"2000-03-03",
"0" //0 bcoz the ID 11 is not there in data2 array
]
]
}
I find this challenging to accomplish. Think of it like a LEFT-JOIN in MySQL.
I referred to this solution but it doesn't work in my case as I don't have the keys in my response.
EDIT: I also need to join the other fields as well.
You can use Array.prototype.map(), find, filter, slice, reduce, concat, includes and Object.assign().
This solution:
Handles arbitrary ordering of the items. The order is read from the headers.
Appends a Balance field only if there is one present in data2.
Joins all other fields (requested by OP, see comments below).
Takes default values as an input and uses them if the data is not present in data1 and data2.
function merge({ data1, data2 }, defaults) {
// get the final headers, add/move 'Balance' to the end
const headers = [...data1[0].filter(x => x !== 'Balance')]
.concat(data2[0].includes('Balance') ? ['Balance'] : []);
// map the data from data1 to an array of objects, each key is the header name, also merge the default values.
const d1 = data1.slice(1)
.map(x => x.reduce((acc, y, i) => ({ ...defaults, ...acc, [data1[0][i]]: y }), {}));
// map the data from data2 to an array of objects, each key is the header name
const d2 = data2.slice(1)
.map(x => x.reduce((acc, y, i) => ({ ...acc, [data2[0][i]]: y }), {}));
// combine d1 and d2
const output = d1.map((x, i) => { // iterate over d1
// merge values from d2 into this value
const d = Object.assign(x, d2.find(y => y['ID'] === x['ID']));
// return an array ordered according to the header
return headers.map(h => d[h]);
});
return { output: [headers, ...output] };
}
const test0 = {
data1: [[ "ID","name","Birthday","other"],["10","thomas","1992-03-17","empty"],["11","Emily","2000-03-03","empty"]],
data2: [["other", "ID", "Balance", "city"],["hello", "10", "$4500", "New York"],["world", "10","$8","Brazil"]]
};
const test1 = {
data1: [["ID","name","Birthday"],["10","thomas","1992-03-17"],["11","Emily","2000-03-03"]],
data2: [["other","ID"],["x","10"],["y","11"]]
};
console.log(merge(test0, { Balance: '$0' }));
console.log(merge(test1, { Balance: '$0' }));
const KEY_ID = "ID";
var data = {
"data1": [
[ "ID", "name", "Birthday" ],
[ "10", "thomas", "1992-03-17" ],
[ "11", "Emily", "2000-03-03" ]
],
"data2": [
[ "Balance", "ID" ],
[ "$4500", "10" ],
[ "$1500", "13" ]
]
}
var merged = Object.keys(data).map(function (key) {
var tmp = data[key].slice();
var heads = tmp.shift();
return tmp.map(function (item) {
var row = {};
heads.forEach(function (head, i) {
row[head] = item[i];
});
return row;
});
}).flat().reduce(function (acc, row) {
var found = acc.find(function (item) {
return row[KEY_ID] === item[KEY_ID];
})
if (!found) {
found = row;
acc.push(found);
} else {
Object.keys(row).forEach(function (head) {
found[head] = row[head];
});
}
return acc;
}, []);
console.log(merged);
This solution is scalable: if you add properties, it will scale the new format.
let a = { "data1": [ ... ],"data2": [ ...] }
let r = a.data1.reduce((r,u,i)=>{
if(i !== 0)
{
let entry = a.data2.filter((a)=> a[1]===u[0])
r.push([...u,entry.length ? entry[0][0] : 0])
}
return r
},[[
"ID",
"name",
"Birthday",
"Balance"
]])
You could abstract all table operations into a class-like:
function Table(array) {
const [head, ...values] = array;
const Entry =(entry) => ({
get(key) { return entry[ head.indexOf(key) ]; },
set(key, value) { entry[ head.indexOf(key) ] = value; }
});
return {
index(name) {
const result = {};
for(const value of values)
result[ value[ head.indexOf(name) ] ] = Entry(value);
return result;
},
*[Symbol.iterator]() {
for(const row of values)
yield Entry(row);
},
addRow(key) { head.push(key); }
};
}
Usable as:
const users = Table(obj.data1);
const balances = Table(obj.data2);
const balanceByID = balance.index("ID");
users.addRow("Balance");
for(const user of users)
user.set("Balance", balanceByID[ user.get("ID") ].get("Balance"));
I have an object as shown below :
[
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"},
{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"},
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}
]
I need to group it like this :
[
[
[
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"}
],
[{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"}],
[{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"}]
],
[
[
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"}
],
[{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}]
]
]
I am using underscore.js to group the elements in the object.
$scope.InitController = function () {
ClientGroupService.GetClientGroupList().then(function (response) {
$scope.groupByTwoFields = [];
$scope.groupByTwoFields = _.groupBy(response.data, function (obj) {
return obj.ClientGroupName + '|' + obj.ControlGroupName;
});
.....
});
};
The output from the above code looks like :
[
[
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"}
],
[{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"}],
[{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"}],
[
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"}
],
[{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}]
]
What do I need to do in order to get the desired output as shown above.
Your code producing the output in the below shown form :
[
[
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"},
{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"}
],
[
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}]
]
Here's a very simple function to do it in vanilla JavaScript, it takes two arguments:
arr The array containing the objects that you want to group.
properties An array of strings with the names of the properties you want to group the objects by, ordered by priority (objects will be ordered by the first property in the array, then the second, etc).
function groupByProperties(arr, properties) {
const groups = {
root: {
array: [],
children: {}
}
};
arr.forEach(obj => {
let group = groups.root;
properties.forEach(propertyKey => {
const property = obj[propertyKey];
if (!group.children.hasOwnProperty(property)) {
const child = {
array: [],
children: {}
}
group.array.push(child.array);
group.children[property] = child;
}
group = group.children[property];
});
group.array.push(obj);
});
return groups.root.array;
}
You would use it as follows:
let data = [
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"},
{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"},
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}
];
console.log(groupByProperties(data, ["ClientGroupName", "ControlGroupName"]));
i did it with just vanillaJS in case the answer above didn't work for you:
var data = [
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"},
{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"},
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}
];
var ClientGroupNames = [];
data.forEach(function(o){
if(ClientGroupNames.indexOf(o.ClientGroupName) < 0){
ClientGroupNames.push(o.ClientGroupName);
}
});
var result = ClientGroupNames.map(function(name){
return data.filter(function(comp){
return comp.ClientGroupName == name ? true : false;
})
}).map(function(grp){
var groupNames = [];
grp.forEach(function(company){
if(groupNames.indexOf(company.ControlGroupName) < 0)
groupNames.push(company.ControlGroupName);
})
return groupNames.map(function(name){
return grp.filter(function(gp){
return gp.ControlGroupName == name ? true : false;
})
})
})
_.groupBy doesn't return an array, it returns an object.
var data = [{
"ClientGroupName": "ABC",
"CompanyName": "AA",
"ControlGroupName": "1"
}, {
"ClientGroupName": "ABC",
"CompanyName": "BB",
"ControlGroupName": "1"
}, {
"ClientGroupName": "ABC",
"CompanyName": "CC",
"ControlGroupName": "1"
}, {
"ClientGroupName": "ABC",
"CompanyName": "DD",
"ControlGroupName": "2"
}, {
"ClientGroupName": "ABC",
"CompanyName": "EE",
"ControlGroupName": "3"
}, {
"ClientGroupName": "DEF",
"CompanyName": "FF",
"ControlGroupName": "1"
}, {
"ClientGroupName": "DEF",
"CompanyName": "GG",
"ControlGroupName": "1"
}, {
"ClientGroupName": "DEF",
"CompanyName": "HH",
"ControlGroupName": "2"
}];
var obj = _.groupBy(data,function (obj) {
return obj.ClientGroupName;
}); // groupBy returns an object, not a array
var result = Object.keys(obj).map(function (key) { return obj[key]; }); // this converts the object to an array
_.each(result,function(obj,index){ // loop through each item in the array
var _obj = _.groupBy(obj,function(obj2){
return obj2.ControlGroupName;
}); // group it by the ControlBroupName and convert it to a array
result[index] = Object.keys(_obj).map(function (key) { return _obj[key]; });
});
console.log("result:\n", result);
You have to groupBy twice:
result = _(data).groupBy('ClientGroupName').map(g =>
_.values(_.groupBy(g, 'ControlGroupName'))
).value()
How would I go about adding all the values within the object?
For example amoutpay": ["4222","1000"] would give me 5222
This is my object:
{
"amoutpay": [ "4222", "1000" ],
"amtpending": [ "778", "4000" ],
"totalcost": [ "5000", "5000" ],
"coursename": [ "Office Automation", "ajaba" ]
}
What I want is to add the values to variables. Would I use split?
var a =
var b =
var c =
You can use Array.prototype.reduce() as shown below:
var obj = {
"amoutpay": [ "4222", "1000" ],
"amtpending": [ "778", "4000" ],
"totalcost": [ "5000", "5000" ],
"coursename": [ "Office Automation", "ajaba" ]
},
a = obj.amoutpay.reduce(function(prevVal, curVal, curInd) {
return +prevVal + +curVal;
}),
b = obj.amtpending.reduce(function(prevVal, curVal, curInd) {
return +prevVal + +curVal;
}),
c = obj.totalcost.reduce(function(prevVal, curVal, curInd) {
return +prevVal + +curVal;
});
console.log( a, b, c );
Or you could go a step further and define your own array method, eg Array.prototype.sum():
var obj = {
"amoutpay": [ "4222", "1000" ],
"amtpending": [ "778", "4000" ],
"totalcost": [ "5000", "5000" ],
"coursename": [ "Office Automation", "ajaba" ]
};
Array.prototype.sum = function() {
return this.reduce(function( prv, cur, ind ) {
return +prv + +cur;
});
};
var a = obj.amoutpay.sum(),
b = obj.amtpending.sum(),
c = obj.totalcost.sum();
console.log( a, b, c );
var obj = {
"amoutpay": [ "4222", "1000" ],
"amtpending": [ "778", "4000" ],
"totalcost": [ "5000", "5000" ],
"coursename": [ "Office Automation", "ajaba" ]
}
var a = addValues(obj.amoutpay);
function addValues(arr) {
return arr.map(function(el) {
return Number(el);
}).reduce(function(prev, curr){
return prev + curr;
})
}
We iterate the object elements and for all arrays we check whether all the elements are numeric. If so, then add them as variables to the window object, so after the loop we will have an amoutpay variable for the input shown in the question. Note, that if a key happens to already be a variable, then this code will override it.
for (var key in obj) {
if (Array.isArray(obj[key])) {
var shouldAdd = true;
for (var index = 0; shouldAdd && index < obj[key].length; index++) {
if (isNaN(obj[key][index])) {
shouldAdd = false;
}
}
if (shouldAdd) {
window[key] = 0;
for (var index = 0; index < obj[key].length; index++) {
window[key] += parseFloat(obj[key][index]);
}
}
}
}
I have a large object of arrays. I need to break down this object into an array of objects. I believe that underscore.js is good tool for this type of object transformation, but I’ve never used that library before. For this example I need to convert the key of each property to a ‘name’ variable in the output array, and than push elements of each property of each object into array's. That’s difficult to explain so below I have a before and after array to help visualize what I’m trying to accomplish. Can I accomplish this task with underscore.js easier than pure javascript ? I’ve attempted this with for loops and if else statements but it got messy quickly, so any help is greatly appreciated.
Before:
var obj = {
"AH5T5TAFXX-001":
["AH5T5TAFXX-001",
{
Bin_reads:2436307,
IC_lot:1,
LabChip_size_bp:410,
LibType:"RNA",
Tot_reads:7386376,
bioSple:193,
internal_controls:5
}, {
Bin_reads:2906003,
IC_lot:1,
LabChip_size_bp:395,
LibType:"RNA",
Tot_reads:6680167,
bioSple:198,
internal_controls:5
}],
"AH5NVVAFXX-002":
["AH5NVVAFXX-002",
{
Bin_reads:2436307,
IC_lot:1,
LabChip_size_bp:410,
LibType:"RNA",
Tot_reads:7386376,
bioSple:193,
internal_controls:5
},
{
Bin_reads:2436307,
IC_lot:1,
LabChip_size_bp:410,
LibType:"RNA",
Tot_reads:6680167,
bioSple:193,
internal_controls:5
}]
};
After:
var arr = [
{
"name": "AH5T5TAFXX-001",
"Bin_reads": [2436307,2906003],
"IC_lot": [1,1],
"LabChip_size_bp": [410,395],
"LibType": ["RNA", "RNA"],
"Tot_reads": [7386376,6680167]
"bioSple": [193,198],
"internal_controls": [5,5]
},{
"name": "AH5T5TAFXX-002",
"Bin_reads": [2436307,2906003],
"IC_lot": [1,1],
"LabChip_size_bp": [410,395],
"LibType": ["RNA", "RNA"],
"Tot_reads": [7386376,6680167]
"bioSple": [193,198],
"internal_controls": [5,5]
}
];
The following is a robust method to flatten your data structure and merge the individual entries. It is agnostic to the number and order of entries:
var result = Object.keys(obj).map((key, index) => {
var entries = obj[key];
var combined = {};
entries.forEach(entry => {
if (typeof entry === 'string') {
combined.name = entry;
} else {
Object.keys(entry).forEach(key => {
if (Array.isArray(combined[key])) {
combined[key].push(entry[key]);
} else {
combined[key] = [entry[key]];
}
});
}
});
return combined;
})
var obj = {
"AH5T5TAFXX-001":
["AH5T5TAFXX-001",
{
Bin_reads:2436307,
IC_lot:1,
LabChip_size_bp:410,
LibType:"RNA",
Tot_reads:7386376,
bioSple:193,
internal_controls:5
}, {
Bin_reads:2906003,
IC_lot:1,
LabChip_size_bp:395,
LibType:"RNA",
Tot_reads:6680167,
bioSple:198,
internal_controls:5
}],
"AH5NVVAFXX-002":
["AH5NVVAFXX-002",
{
Bin_reads:2436307,
IC_lot:1,
LabChip_size_bp:410,
LibType:"RNA",
Tot_reads:7386376,
bioSple:193,
internal_controls:5
},
{
Bin_reads:2436307,
IC_lot:1,
LabChip_size_bp:410,
LibType:"RNA",
Tot_reads:6680167,
bioSple:193,
internal_controls:5
}]
};
var result = Object.keys(obj).map((key, index) => {
var entries = obj[key];
var combined = {};
entries.forEach(entry => {
if (typeof entry === 'string') {
combined.name = entry;
} else {
Object.keys(entry).forEach(key => {
if (Array.isArray(combined[key])) {
combined[key].push(entry[key]);
} else {
combined[key] = [entry[key]];
}
});
}
});
return combined;
})
console.log(result);
// iterate through the keys of 'obj'
// create an array element for each key
console.log( Object.keys(obj).map( function(key){
// 'result' is the element to be returned for each key
// every property value of 'obj' is an array
// whose first element represents the name of the new object
var result = {
'name': obj[key][0]
};
if( obj[key].length > 1 ){
// pull all attribute names of second element of array
// and set them to empty arrays in the transformed object
var properties = Object.keys( obj[key][1] );
properties.forEach( function( prop ){ result[prop] = []; } );
// iterate through the input array (skipping the first element)
// and add a value to the matching array of 'result'
for( var i=1; i<obj[key].length; i++ )
properties.forEach( function( prop ){ result[prop].push( obj[key][i][prop] ); } );
}
return result;
}) );
This function:
function solution(A)
{
var result = [];
for (var key in A)
{
var subArr = A[key];
var newObj = {};
result.push(newObj);
newObj.name = key;
for (var i=1, ii=subArr.length; i<ii; i++)
{
var subSubObj = subArr[i];
for (var subSubKey in subSubObj)
{
if (!newObj[subSubKey])
newObj[subSubKey] = [subSubObj[subSubKey]];
else
newObj[subSubKey].push(subSubObj[subSubKey]);
}
}
}
return result;
}
will return this object if given your input:
[
{
"name": "AH5T5TAFXX-001",
"Bin_reads": [2436307,2906003],
"IC_lot": [1,1],
"LabChip_size_bp": [410,395],
"LibType": ["RNA","RNA"],
"Tot_reads": [7386376,6680167],
"bioSple": [193,198],
"internal_controls": [5,5]
},
{
"name": "AH5NVVAFXX-002",
"Bin_reads": [2436307,2436307],
"IC_lot": [1,1],
"LabChip_size_bp": [410,410],
"LibType": ["RNA","RNA"],
"Tot_reads": [7386376,6680167],
"bioSple": [193,193],
"internal_controls": [5,5]
}
]
JSFiddle example (logs to console, so open dev tools): https://jsfiddle.net/mpey5wfv/
In a very very straight forward way, it'd look like this:
// output array
var arr = [];
// iterating the "obj" object
for (prop1 in obj) {
// temporary object
var newObj = {
// setting the property name
name : prop1,
};
// iterating the array of objects
// skipping the first item. it is a string
for (var i = 1; i < obj[prop1].length; i++) {
// iterating the object that's inside the array
for (prop2 in obj[prop1][i]) {
// checking if the new property already exists in the new obj
// if not, create it
if (!newObj[prop2]) {
newObj[prop2] = [];
}
// adding the values from the two objects into an array in a single object
newObj[prop2].push(obj[prop1][i][prop2]);
}
}
arr.push(newObj);
}
console.log(JSON.stringify(arr, false, "\t")) outputs
[
{
"name": "AH5T5TAFXX-001",
"Bin_reads": [
2436307,
2906003
],
"IC_lot": [
1,
1
],
"LabChip_size_bp": [
410,
395
],
"LibType": [
"RNA",
"RNA"
],
"Tot_reads": [
7386376,
6680167
],
"bioSple": [
193,
198
],
"internal_controls": [
5,
5
]
},
{
"name": "AH5NVVAFXX-002",
"Bin_reads": [
2436307,
2436307
],
"IC_lot": [
1,
1
],
"LabChip_size_bp": [
410,
410
],
"LibType": [
"RNA",
"RNA"
],
"Tot_reads": [
7386376,
6680167
],
"bioSple": [
193,
193
],
"internal_controls": [
5,
5
]
}
]