I have two arrays:
var columns = ["Date", "Number", "Size", "Location", "Age"];
var rows = [
["2001", "5", "Big", "Sydney", "25"],
["2005", "2", "Med", "Melbourne", "50"],
["2012", "20", "Huge", "Brisbane", "80"]
];
I'm trying to combine them into a javascript object for each item in the rows array. After that, I want to push each object into a new array.
Like:
var newarray = [];
//'thing' should be the same structure for each row item
var thing = {
"Date": "2001",
"Number": "5",
"Size": "Big",
"Location": "Sydney",
"Age": "25"
}
newarray.push(thing);
I can do this when I know the names of the columns, but I need to be able to store the data in this way when the column name is unknown - i.e. based on the indexes of the columns array.
I tried it like this before:
for (var y = 0; y < rows.length; y++) {
for (var i = 0; i < columns.length; i++) {
thing[columns[i]] = rows[i][i];
}
newarray.push(thing)
}
The code above only stored the first item again and again (according to rows.length).
I don't understand how to combine the column names with the rows to create an array of objects. The fact that 'rows' contains arrays is especially confusing..
12 Answers 12
You could as well do this in a more data-centric manner:
const columns = ["Date", "Number", "Size", "Location", "Age"]
const rows = [
["2001", "5", "Big", "Sydney", "25"],
["2005", "2", "Med", "Melbourne", "50"],
["2012", "20", "Huge", "Brisbane", "80"]
]
const result = rows.map(row =>
row.reduce(
(result, field, index) => ({ ...result, [columns[index]]: field }),
{}
)
)
console.log(result)
UPDATE 2022: Using a now more common syntax (short functions)
Here's the original snippet:
var columns = ["Date", "Number", "Size", "Location", "Age"];
var rows = [
["2001", "5", "Big", "Sydney", "25"],
["2005", "2", "Med", "Melbourne", "50"],
["2012", "20", "Huge", "Brisbane", "80"]
];
var result = rows.map(function(row) {
return row.reduce(function(result, field, index) {
result[columns[index]] = field;
return result;
}, {});
});
console.log(result)
This way you would not have to deal with the temporary arrays.
In case your code should work on ancient browsers as well, I'd recommend to take a look at lodash for using map + reduce.
1 Comment
Create a new thing object at the beginning of each iteration of the outer loop. If you don't do so, each time you say thing[columns[i]] you'll be overwriting the properties of the same object, and when you push it into newarray what you'll end up with is an array full of references to the same object. Also, inside the loop be sure you get the indexes right (you've currently got [i][i] instead of [y][i]):
var newarray = [],
thing;
for(var y = 0; y < rows.length; y++){
thing = {};
for(var i = 0; i < columns.length; i++){
thing[columns[i]] = rows[y][i];
}
newarray.push(thing)
}
"The fact that 'rows' contains arrays is especially confusing.."
For your sample data rows.length will be 3, and rows[0] is the array:
["2001", "5", "Big", "Sydney", "25"]
rows[0][3] is "Sydney".
Using that as an example you should be able to see what rows[y][i] will give you for each value of y and i...
Comments
In case you are using Underscore.js there is _.object(list, [values])
And here's how it's implemented:
_.object = function(list, values) {
if (list == null) return {};
var result = {};
for (var i = 0, length = list.length; i < length; i++) {
if (values) {
result[list[i]] = values[i];
} else {
result[list[i][0]] = list[i][1];
}
}
return result;
};
1 Comment
Using functional would be like nnnnnn said but with a minor correction
var columns = ["Date", "Number", "Size", "Location", "Age"];
var rows = [
["2001", "5", "Big", "Sydney", "25"],
["2005", "2", "Med", "Melbourne", "50"],
["2012", "20", "Huge", "Brisbane", "80"]
];
var result = rows.map(function(row) {
return row.reduce(function(result, field, index) {
result[columns[index]] = field;
return result
}, {});
});
Comments
You need to specify the right row. You are using the column. Replace rows[i][i] with rows[y][i]. Also, looks like you are re-using the same thing object over and over. Instead you should define it anew each iteration through the array (var thing = {};).
var newarray = [];
for (var y = 0; y < rows.length; y++) {
var thing = {};
for (var i = 0; i < columns.length; i++) {
thing[columns[i]] = rows[y][i];
}
newarray.push(thing);
}
4 Comments
var thing = [] each iteration of the loop. Your JSFiddle doesn't show that.thing is a object, not an Array{} instead of []). Also the JSFiddle: jsfiddle.net/V42Hx/3 You can use this function following ES6 code:
const assemblyData = ( columns, rows) => {
return rows.map((row) => {
return row.reduce((res, field, index) => {
res[columns[index]] = field;
return res
}, {});
});
}
// short version
const assemblyDataMin = (columns, rows) =>
rows.map(row =>
row.reduce((res, field, index) => {
res[columns[index]] = field;
return res;
}, {})
);
Comments
With modern day JS, you can use Object.fromEntries() to build the object for you:
const columns = ["Date", "Number", "Size", "Location", "Age"];
const rows = [["2001", "5", "Big", "Sydney", "25"],["2005", "2", "Med", "Melbourne", "50"],["2012", "20", "Huge", "Brisbane", "80"]];
const res = rows.map(row => Object.fromEntries(
columns.map((key, i) => [key, row[i]]))
);
console.log(res);
Above, I'm building an array of the form [[key1, value1], [key2, value2], ...] with .map() for each row in rows, and the passing that into the Object.fromEntries() call, which builds an object for us from the key-value pair array of the form {key1: value1, key2: value2}.
Comments
You can use Array.prototype.map() combined with Object.fromEntries()
Code:
const columns = ["Date", "Number", "Size", "Location", "Age"];
const rows = [["2001", "5", "Big", "Sydney", "25"],["2005", "2", "Med", "Melbourne", "50"],["2012", "20", "Huge", "Brisbane", "80"]]
const result = rows.map(r => Object.fromEntries(r.map((c, i) => [columns[i], c])))
console.log(result)
Comments
i think my solution is solve your problem
code:
var keys = columns,
values = rows,
finalarray = [];
values.forEach((data,index) =>{
var objJSON = new Object();
for (i = 0; i < keys.length; i++) {
objJSON[keys[i]] = data[i];
}
finalarray.push(objJSON);
});
answer:
console.log(finalarray)
[{
"Date" : "2001",
"Number" : "5",
"Size":"Big",
"Location":"Sydney",
"Age":"25"
},
...
}]
Comments
const columns = ["Date", "Number", "Size", "Location", "Age"]
const rows = [
["2001", "5", "Big", "Sydney", "25"],
["2005", "2", "Med", "Melbourne", "50"]
]
const a = Array.from(rows, r => Object.fromEntries(
Array.from(r, (v, i) => [columns[i], v])
));
console.log(a)
Comments
Instead of looping over the entire table, you can also use the columns array to generate a Row class (using defineProperty) and then use that row class to wrap the row arrays in your rows array. The resulting array of Row objects is then tied to the original rows array, such that changes in one are reflected in the other. Depending on your use case, this could be useful or a problem. A working example is given in the snippet below.
var columns = ["Date", "Number", "Size", "Location", "Age"];
var rows = [
["2001", "5", "Big", "Sydney", "25"],
["2005", "2", "Med", "Melbourne", "50"],
["2012", "20", "Huge", "Brisbane", "80"]
];
var table = create_table(columns, rows);
//
for (var i = 0; i<table.length; i++) {
document.writeln("The thing in " + table[i].Location + " is " + table[i].Size + "<br/>");
}
// The rows in table are still tied to those in the rows variable
table[0].Size = "Small";
document.writeln(JSON.stringify(rows[0]));
function create_table(columns, rows) {
// Create a Row class with the given columns
for (var i=0; i<columns.length; i++) {
var c = columns[i];
Object.defineProperty(Row.prototype, c, {
enumerable: true,
get: getter(i),
set: setter(i),
});
}
// Wrap the rows in row objects and return the resulting array
var r = new Array(rows.length);
for (var i=0; i<rows.length; i++) {
r[i] = new Row(rows[i]);
}
return r;
function Row(row) { this._ = row; }
// Generators for the getter and setter functions, with variable i stored in a closure.
function getter(i) {
return function(){
return this._[i];
};
}
function setter(i) {
return function(val){
return this._[i] = val;
};
}
}