0

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)
});
1
  • You can do data.flatMap(item => [item.firstColumn, item.secondColumn]), but that of course changes order Commented May 20, 2022 at 0:39

3 Answers 3

4

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

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

1 Comment

That answers my question, thank you! I agree that this is more difficult to read than the original but I appreciate the response.
0

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.

3 Comments

I never said readability is the most important part. If you have to do this for a 10,000 element array on every clock tick, readability goes out the window in favor of performance. Additionally, the reduce operation would scale to more than 2 properties, while still maintaining one iteration.
@RobbyCornelissen Apologies, I should have said "I agree with Robby in that you're potentially losing readability if you move this to a reduce function"
No apologies needed at all. Was just clarifying my stance :)
0

Looping your current logic

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

Generalized reduce()

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


Zip (original answer)

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

Comments

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.