0

I am completely new to JavaScript, and taking a beginner level course at school.

I have an assignment in which we are asked to create a function that converts a 2D array into a dictionary, by using column headers as a key and data as a value for each row.

I think I know how to separate the first row (to use as headers) and the rest of the rows (to use as rows), but I am having a trouble converting this into a dictionary.

Here is what I have written so far:

function rowsToObjects(data) {
    var headers = data[1];
    data.shift();
    //var rows = alert(data);
    var rows = alert(data.slice(1));
}

And here is the example of what the output should look like:

const headers = ['a', 'b', 'c'];//Should not be hardcoded - subject to change depending on the grader
const rows = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];//Should not be hardcoded - subject to change depending on the grader
const result = rowsToObjects({headers, rows}) 
console.log(result);
// [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}, {a: 7, b: 8, c: 9}];

I would have known how to create a dictionary for each row if I could use a for loop, but we are not allowed to use while loops, for loops, for ... in loops, for ... of loops, forEach method, so I am struggling with coming up with a way to do this, and make my output look like the ones that is shown in the example.

Any help is welcome, and thank you very much!

7
  • For every row, create a new dictionary and fill it with properties. Where exactly do you have trouble? Commented Sep 22, 2019 at 15:15
  • Thank you for the comment. If what I have so far is correct, then I think I am ok with splitting the array into "header" and "rows". But I am not sure how to make it into a dictionary so I am struggling with that. Commented Sep 22, 2019 at 15:16
  • Seems a bit more advanced task than entry level beginner Commented Sep 22, 2019 at 15:16
  • Nice question. If this is an intro course they're doing better than the ones around my area. First thing is that you're passing an object to your function when you write ` { headers, rows } `, not an array. So you're likely having a problem solving this because you're attempting to use array methods on an object, which will error. Commented Sep 22, 2019 at 15:18
  • @charlietfl plus I find this JavaScript syntax very not intuitive Commented Sep 22, 2019 at 15:20

3 Answers 3

2

You can use Array.prototype.reduce on the rows array to iterate over each array in the rows 2-D array.

Then for each array in the 2-D array create a temporary object by using Array.prototype.reduce to map the values from headers corresponding to each array value of the rows array using the index i:

const headers = ['a', 'b', 'c'];
const rows = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const result = rowsToObjects(headers, rows) 
console.log(result);
// [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}, {a: 7, b: 8, c: 9}];

function rowsToObjects(headers, rows){
  return rows.reduce((acc, e, idx) =>  {
     acc.push(headers.reduce((r, h, i)=> {r[h] = e[i]; return r; }, {}))
     return acc;
  }, []);
}

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you @Fullstack guy but we are not allowed to use foreach, for, while, for...in, for...of loops :( Is there any other way I can solve this problem?
@NathanBell I have used only reduce to get the expected output, but reduce internally will use loops to go over each element. So unless you have static data and want to hard code indexes there is no other option.
Could you please explain to me what the 3 arguments for reduce mean? I tried to look it up, but I can only find .reduce with 2 arguments.
@Nathan Bell the three arguments are: 1. the accumulator, which is the object you are reducing to. 2. The element from the array when you iterate 3. The index of the element in the array
1

You could use Array.reduce to loop throgh all arrays and reduce them to objects.

function arrayToObjects(rows){
  const headers = rows.shift();//shift headers out of rows
  return rows.map(rowsToObjects);
  function rowsToObjects(row) {
    return  row.reduce((obj,e,i)=>{
      obj[headers[i]]=e;
      return obj;
    },{})
  }
}
console.log(arrayToObjects([['a', 'b', 'c'],[1, 2, 3], [4, 5, 6], [7, 8, 9]]));

10 Comments

Thank you for your help, @TheMaster. We are not allow to hardcode "data" since it is subject to change. Is there a way to do this without hardcoding? Could you please tell me whether my way of creating headers and rows is correct? Also, is there a way to call const result = rows.map(rowsToObjects); inside the rowsToObjects function?
There's no advantage in using reduce over a simple loop, especially for a beginner.
@Bergi It seems He isn't allowed to use loops
Oh. Well then your answer is ok I guess :-) I'd recommend to reduce over the headers though, just in case the number of columns is different.
@TheMaster I mean instead of doing row.reduce(…), rather go for headers.reduce((obj, header, i) => { obj[header] = row[i]; return obj}, {}). That guarantees that the objects always have the same properties, no matter how jagged the array is. (Also it avoids the nested bracket notation)
|
1

Looping through rows using map and then using reduce to associate each cell (c) from a row (r) to a header using the index (i).

Here is a one-liner to be fancy:

function rowsToObjects(rows, headers) {
  return rows.map(r => r.reduce((o, c, i) => Object.assign(o, { [headers[i]]: c }), {}))
}

4 Comments

Could you please explain to me what the 3 arguments for reduce mean? I tried to look it up, but I can only find .reduce with 2 arguments. Also says TypeError: Cannot read property '0' of undefined
The first parameter (o) is the object we are building. The second parameter (c) is the cell or value (1 to 9). The third parameter (i) is the index. The function rowsToObjects takes as first parameter the array of rows and second parameter the array of headers.
what is i? Is it the index as a row number(ranging from r0 to r2), or as a column number (from c0 to c2)?
i is the index returned by the reduce function while it's looping through rows.

Your Answer

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.