Is it possible to combine map() and concat() in the following code to make it cleaner/shorter?
const firstColumnData = data.map((item: any) => {
return item.firstColumn;
});
const secondColumnData = data.map((item: any) => {
return item.secondColumn;
});
const allData = firstColumnData.concat(secondColumnData);
For context, later in the file allData is mapped through to populate data into columns. The specific data depends on which page is calling the component.
Basically, I am wondering if I can skip the declaration of firstColumnData and secondColumn data and assign the value to allData directly. This is an example of how I tried to refactor, but it did not work. (white page, could not render)
const allData = data.map((item: any => {
return item.firstColumn.concat(item.secondColumn)
});
You can use a single reduce() operation. Arguably, what you save by only having to iterate once, you lose in readability:
const data =[
{firstColumn: 1, secondColumn: 2},
{firstColumn: 3, secondColumn: 4}
];
const result = data.reduce((a, {firstColumn, secondColumn}, i, {length}) => {
a[i] = firstColumn;
a[i + length] = secondColumn;
return a;
}, []);
console.log(result);
I agree with Robby that readability is probably the most important part in this.
You could one line this though, as:
const allData = [...data.map(item => item.firstColumn), ...data.map(item.secondColumn)];
but in this case you're still looping twice, so you haven't saved any computation, you've just made it shorter to write.
My original answer below is, of course, performant as the proverbial January molasses even though I like the shape of it.
A little testing shows that just putting your current logic into a loop offers about the same or better performance than a generalized version RobbyCornelissen's answer (unless you unroll the loop in the reduce...) and has the benefit of simplicity. It relies on defining an array of column properties to iterate over.
const
data = [{ firstColumn: 1, secondColumn: 2 }, { firstColumn: 3, secondColumn: 4 }],
columns = ['firstColumn', 'secondColumn'],
result = [].concat(...columns.map(col => data.map((item) => item[col])));
console.log(result);
const
data = [{ firstColumn: 1, secondColumn: 2 }, { firstColumn: 3, secondColumn: 4 }],
columns = ['firstColumn', 'secondColumn'],
result = data.reduce((a, item, i, { length }) => {
for (let j = 0; j < columns.length; j++) {
a[i + length * j] = item[columns[j]]
}
return a
}, []);
console.log(result);
If the properties are guaranteed to be in order you could 'zip' the Object.values. This will handle any number of properties without explicit desctructuring.
const data = [
{ firstColumn: 1, secondColumn: 2 },
{ firstColumn: 3, secondColumn: 4 }
];
const result = zip(...data.map(Object.values)).flat()
console.log(result)
<script>
/**
* @see https://stackoverflow.com/a/10284006/13762301
*/
const zip = (...rows) => [...rows[0]].map((_, c) => rows.map((row) => row[c]));
</script>
But to avoid relying on property order you can still destructure.
const result = zip(...data.map(({ firstColumn, secondColumn }) => [firstColumn, secondColumn])).flat()
see: Javascript equivalent of Python's zip function for more discussion on 'zip'.