ccocker
ccocker

Reputation: 1236

Pushing Values into Array

I have a problem with populating an array based on another array.

It seems when I push a value onto a specific index in the array, it is populating all indexes.

Code

import { Component, VERSION } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  name = 'Angular ' + VERSION.major;
  public matrix: number[] = [
    1, 2, 3, 4, 5, 6, 7, 8, 9.1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
    23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
    42, 43, 44, 45,
  ];
  public matrixColumns: number[][] = [];
  public expectedMatrixColumns: number[][] = [
    [1, 10, 19, 28, 37],
    [2, 11, 20, 29, 38],
    [3, 12, 21, 30, 39],
    [4, 13, 22, 31, 40],
    [5, 14, 23, 32, 41],
    [6, 15, 24, 33, 42],
    [7, 16, 25, 34, 43],
    [8, 17, 26, 35, 44],
    [9, 18, 27, 36, 45],
  ];
  public numberofColumns: number = 9;
  columnStartIndex: number = 0;

  constructor() {
    this.createColumnMatrix();
  }

  createColumnMatrix() {
    let columnsMatrix = [];
    let numberRows = this.matrix.length / this.numberofColumns;
    let matrixIndex = 0;

    for (let index = 0; index < this.numberofColumns; index++) {
      this.matrixColumns.push([]);
    }
    let columnIndex: number = 0;
    this.matrix.forEach((number, matrixIndex) => {
      debugger;
      this.matrixColumns[columnIndex].push(this.matrix[matrixIndex]);
      debugger;
      matrixIndex = matrixIndex + 1;
      columnIndex = columnIndex + 1;
      if (columnIndex > this.numberofColumns - 1) {
        columnIndex = 0;
      }
    });
  }
}

Demo Project

Here is a JavaScript version that reproduces the problem:

class AppComponent {
  matrix = [
    1, 2, 3, 4, 5, 6, 7, 8, 9.1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
    23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
    42, 43, 44, 45,
  ];
  matrixColumns = [];
  expectedMatrixColumns = [
    [1, 10, 19, 28, 37],
    [2, 11, 20, 29, 38],
    [3, 12, 21, 30, 39],
    [4, 13, 22, 31, 40],
    [5, 14, 23, 32, 41],
    [6, 15, 24, 33, 42],
    [7, 16, 25, 34, 43],
    [8, 17, 26, 35, 44],
    [9, 18, 27, 36, 45],
  ];
  numberofColumns = 9;
  columnStartIndex = 0;

  constructor() {
    this.createColumnMatrix();
  }

  createColumnMatrix() {
    let columnsMatrix = [];
    let numberRows = this.matrix.length / this.numberofColumns;
    let matrixIndex = 0;

    for (let index = 0; index < this.numberofColumns; index++) {
      this.matrixColumns.push(columnsMatrix);
    }
    let columnIndex = 0;
    this.matrix.forEach((number, matrixIndex) => {
      this.matrixColumns[columnIndex].push(this.matrix[matrixIndex]);
      matrixIndex = matrixIndex + 1;
      columnIndex = columnIndex + 1;
      if (columnIndex > this.numberofColumns - 1) {
        columnIndex = 0;
      }
    });
  }
}

let component = new AppComponent();
for (let row of component.matrixColumns) {
    console.log(JSON.stringify(row));
}

Problem

If you look at this line in the code:

this.matrixColumns[columnIndex].push(this.matrix[matrixIndex]);

It is pushing the first value in the array (matrix which is 1), into every index in my second array matrixColumns.

Expected output

[1, 10, 19, 28, 37]
[2, 11, 20, 29, 38]
[3, 12, 21, 30, 39]
[4, 13, 22, 31, 40]
[5, 14, 23, 32, 41]
[6, 15, 24, 33, 42]
[7, 16, 25, 34, 43]
[8, 17, 26, 35, 44]
[9, 18, 27, 36, 45]

Actual output

[1,2,3,4,5,6,7,8,9.1,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45]
[1,2,3,4,5,6,7,8,9.1,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45]
[1,2,3,4,5,6,7,8,9.1,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45]
[1,2,3,4,5,6,7,8,9.1,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45]
[1,2,3,4,5,6,7,8,9.1,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45]
[1,2,3,4,5,6,7,8,9.1,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45]
[1,2,3,4,5,6,7,8,9.1,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45]
[1,2,3,4,5,6,7,8,9.1,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45]
[1,2,3,4,5,6,7,8,9.1,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45]

Upvotes: 0

Views: 87

Answers (3)

trincot
trincot

Reputation: 351359

The problem is that you only have one columnsMatrix array. After pushing its reference to this.matrixColumns repeatedly, you end up with multiple references to the same array. So whether you then push to this.matrixColumns[0] or to this.matrixColumns[1] doesn't make a difference, ... you're always pushing to the same array.

You can solve this by pushing a new array unto this.matrixColumns at every call of push.

So replace:

this.matrixColumns.push(columnsMatrix);

with:

this.matrixColumns.push([]);

Simplified code

Not your question, but you can do this as follows:

this.matrixColumns = Array.from({length: this.numberofColumns}, (_, i) =>
    Array.from({length: numberRows}, (_, j) => matrix[i + j*numberRows])
);

let matrix = [
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
    23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
    42, 43, 44, 45,
];
let numberofColumns = 9;
let numberofRows = Math.ceil(matrix.length / numberofColumns);
// logic
let matrixColumns = Array.from({length: numberofColumns}, (_, i) =>
    Array.from({length: numberofRows}, (_, j) => matrix[i + j*numberofRows])
);
// display
for (const row of matrixColumns) console.log(JSON.stringify(row));

Upvotes: 0

Mark Homer
Mark Homer

Reputation: 1035

you need two dimensions something like

this.matrixColumns[columnIndex][matrixIndex].push(this.matrix[columnIndex][matrixIndex]);

Upvotes: 0

R4ncid
R4ncid

Reputation: 7139

you can do something like this

const buildMatrix = (data, columns) => data.reduce((res, d, i) => {
  const row = i % columns
  const rowData = [...(res[row] || []), d]
  res[row] = rowData
  return res
}, [])

const data = [
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
    23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
    42, 43, 44, 45,
  ];
  
const matrix = buildMatrix(data, 9)

console.log(matrix)

Upvotes: 3

Related Questions