Problem
I am wondering if I could implement this in a cleaner, more elegant, strictly functional way:
const convert2dArrayToJsonList = (array) => {
if (!is2dArrayParsableToJsonList(array)) {
throw new Error("The 2D array cannot be converted to a json list" + array);
}
const propertyKeys = array[0];
return array
.slice(1)
.map( row => {
return row.reduce( (accumulatedElement, propertyValue, currentIndex, array) => {
accumulatedElement[propertyKeys[currentIndex]] = propertyValue;
return accumulatedElement;
}, {});
});
}
The implementation of is2dArrayParsableToJsonList(array) is not relevant in this context, it does what it says.
The 2D array parameter has the property keys in the top row and all other rows represent individual elements in the list.
Solution
Here’s what I’ve come up with;
import expect from 'expect';
const is2dArrayParsableToJsonList = () => true;
const convert2dArrayToJsonList = (array) => {
if (!is2dArrayParsableToJsonList(array)) {
throw new Error("The 2D array cannot be converted to a json list" + array);
}
const [propertyKeys, ...rows] = array;
const rowToObject = row => Object.assign(... propertyKeys.map( (key,idx) => ({ [key]: row[idx] })));
return rows.map(rowToObject);
}
const input = [
['foo', 'bar', 'baz'],
[1,2,3],
[4,5,6]
];
const output = [
{foo:1, bar:2, baz:3},
{foo:4, bar:5, baz:6},
];
expect(convert2dArrayToJsonList(input)).toEqual(output);
Core idea is that map gives you both a value and index. So when you map over the keys, we see ‘foo/1’, ‘bar/2’, ‘baz/3’.