31

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..

isherwood
61.4k16 gold badges122 silver badges173 bronze badges
asked Feb 13, 2012 at 6:08

12 Answers 12

34

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.

answered Feb 13, 2012 at 6:42
Sign up to request clarification or add additional context in comments.

1 Comment

This led me in the right direction...but this ended up being shorter:riptutorial.com/javascript/example/8628/… removing the rows.map and still worked.
16

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...

answered Feb 13, 2012 at 6:39

Comments

4

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;
};
answered Nov 1, 2012 at 18:26

1 Comment

+1. It's good to know how to do this with pure javascript, but why reinvent the wheel? This is the best solution IMHO. It's important to know/use underscore or lodash.
3

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
 }, {});
});
answered Sep 18, 2013 at 16:22

Comments

1

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);
 }
answered Feb 13, 2012 at 6:11

4 Comments

Thanks, I tried it that way, and I'm having the same problem. See: JSFiddle. Am I missing something?
@tamarasaurus, did you see my latest update? I added a part specifying that you need to set var thing = [] each iteration of the loop. Your JSFiddle doesn't show that.
@BenLee, thing is a object, not an Array
@epoch, you're right, it was a typo. updated my answer to make a new object each time (just using {} instead of []). Also the JSFiddle: jsfiddle.net/V42Hx/3
1

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;
 }, {})
 );

Link to examples

answered Dec 11, 2017 at 20:22

Comments

1

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}.

answered Jul 3, 2022 at 11:37

Comments

1

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)

answered Jul 3, 2022 at 12:15

Comments

0

you just need to reset thing

 for(var y = 0; y < rows.length; y++){
 for(var i = 0; i < columns.length; i++){
 thing[columns[i]] = rows[y][i];
 }
 newarray.push(thing);
 thing = {}; 
 }

see update : fiddle

answered Feb 13, 2012 at 6:31

Comments

0

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"
},
...
}]
answered Nov 29, 2016 at 7:11

Comments

0

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)

answered Sep 28, 2024 at 2:13

Comments

-1

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;
 };
 }
}

answered Aug 29, 2015 at 14:00

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.