0

I have a matrix response array:

matrixArray = [
                {Responded: 1, RowName: row1, ColName: col1},
                {Responded: 2, RowName: row1, ColName: col2},
                {Responded: 0, RowName: row1, ColName: col3},
                {Responded: 0, RowName: row2, ColName: col1},
                {Responded: 0, RowName: row2, ColName: col2},
                {Responded: 1, RowName: row2, ColName: col3},
                {Responded: 1, RowName: row3, ColName: col1},
                {Responded: 0, RowName: row3, ColName: col2},
                {Responded: 1, RowName: row3, ColName: col3},
                ...
                ...
              ];

It tells that how many times a column has been responded for a row. I need above array of objects in the following format:

matrixArray = [
                {
                  RowName: row1,
                  col1: 1,           //Here '1' is no. of times column responded
                  col2: 2,
                  col3: 0
                },
                {
                  RowName: row2,
                  col1: 0,
                  col2: 0,
                  col3: 1
                },
                {
                  RowName: row3,
                  col1: 1,
                  col2: 0,
                  col3: 1
                },
              ];

I am using TypeScript for this. Thanks.

4
  • Please share your attempts. Commented Jan 20, 2019 at 9:14
  • You can edit your question. Also, as I said above, you're supposed to show what you tried before people help you. At least share what your approach is and what you can't figure out. Commented Jan 20, 2019 at 9:23
  • I've had an answer ready, I'm going to post it anyway before I lose track of it. Please make an effort to show your attempts next time. Commented Jan 20, 2019 at 17:55
  • Apologies @Jeto but had some connection probs so not able to post my attempts. I was making use of forEach and .filter on the array. My plan was to get the rows first in a different array, and then push the columns respective to it. But that plan didn't work actually. Commented Jan 21, 2019 at 2:58

2 Answers 2

1

You can make use of Array.reduce and Object.values to obtain the desired result:

const matrixArray = [
  {Responded: 1, RowName: 'row1', ColName: 'col1'},
  {Responded: 2, RowName: 'row1', ColName: 'col2'},
  {Responded: 0, RowName: 'row1', ColName: 'col3'},
  {Responded: 0, RowName: 'row2', ColName: 'col1'},
  {Responded: 0, RowName: 'row2', ColName: 'col2'},
  {Responded: 1, RowName: 'row2', ColName: 'col3'},
  {Responded: 1, RowName: 'row3', ColName: 'col1'},
  {Responded: 0, RowName: 'row3', ColName: 'col2'},
  {Responded: 1, RowName: 'row3', ColName: 'col3'}
];

const result = Object.values(matrixArray.reduce((result, entry) => {
  if (!(entry.RowName in result)) {
    result[entry.RowName] = {RowName: entry.RowName};
  }
  if (!(entry.ColName in result[entry.RowName])) {
    result[entry.RowName][entry.ColName] = 0;
  }
  result[entry.RowName][entry.ColName] += entry.Responded;
  return result;
}, {}));

console.log(result);

Note that I didn't type the variables to make it runnable here, feel free to do so since you're using Typescript.

Explanation:

  • Array.reduce loops over the array and builds a RowName => {RowName, col1, col2, col3} map (object) by incrementing by the corresponding Responded amount on each iteration),
  • Object.values then transforms that back into an array.
Sign up to request clarification or add additional context in comments.

Comments

1

You can use reduce and Object.values like this:

const matrixArray = [{Responded:1,RowName:'row1',ColName:'col1'},{Responded:2,RowName:'row1',ColName:'col2'},{Responded:0,RowName:'row1',ColName:'col3'},{Responded:0,RowName:'row2',ColName:'col1'},{Responded:0,RowName:'row2',ColName:'col2'},{Responded:1,RowName:'row2',ColName:'col3'},{Responded:1,RowName:'row3',ColName:'col1'},{Responded:0,RowName:'row3',ColName:'col2'},{Responded:1,RowName:'row3',ColName:'col3'}]

const merged = matrixArray.reduce((acc, {Responded,RowName,ColName}) => {
       acc[RowName] = acc[RowName] || {RowName};
       acc[RowName][ColName] = (acc[RowName][ColName] + Responded) || Responded;
       return acc;
   }, {});

const output = Object.values(merged);
console.log(output)

Here's a shorter version of the above code:

const matrix = [{Responded:1,RowName:'row1',ColName:'col1'},{Responded:2,RowName:'row1',ColName:'col2'},{Responded:0,RowName:'row1',ColName:'col3'},{Responded:0,RowName:'row2',ColName:'col1'},{Responded:0,RowName:'row2',ColName:'col2'},{Responded:1,RowName:'row2',ColName:'col3'},{Responded:1,RowName:'row3',ColName:'col1'},{Responded:0,RowName:'row3',ColName:'col2'},{Responded:1,RowName:'row3',ColName:'col3'}],
  
output = Object.values(matrix.reduce((a, {Responded,RowName,ColName}) => (
    (a[RowName] = a[RowName] || {RowName})[ColName] = Responded, a), {}));

console.log(output);

3 Comments

@Mr.A just a heads up: The accepted answer has the column names hard coded inside the reduce. It won't work if there's another column named col4.
@adiga Fixed that--I did suppose these columns were specific anyway. As a note, this one doesn't do well if several entries have the same RowName / ColName (in which case it would be logical to increment the Responded count each time). Not sure this is possible though (probably not!)
@Jeto Yeah, I'd have to add a ternary in between to handle that. Looking at OP's data, I assumed there won't be any duplicates for rows and columns.

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.