0

I have created a function that is designed to merge multiple multidimensional arrays together

The input 'table' is currently 2 arrays contained in objects, the function is designed to run each time a command is run(not very efficient I know, but it is for a highschool project where this is required)

Printing the input looks like:

[ [ [ 'a', 1 ], [ 'b', 1 ] ], [ [ 'a', 1 ] ] ]

Expecting the resulting table to look like this every time I would run the function:

[ [ 'a', 2 ], [ 'b', 1 ] ]

Instead of incrementing 'tempTable[u][1]' it increments the array connected to table[0] of the input.

Printing the original array which was [ [ 'a', 1 ], [ 'b', 1 ] ] would now show 'a' incrementing by 1 each time the code was run.

I have no idea why it is incrementing the original array instead of just 'tempArray' each time, would somebody be able to explain to me why it increments the original table?

P.S. It is the fault of this function, if I comment out the line that should increment 'tempTable' by 1, the original table doesn't change.

function combineTable(table) {
  var tempTable = table[0];
  for (var i = 1; i < table.length; i++) { //each table
    for (var u = 0; u < tempTable.length; u++) { //temptable values
      for (var y = 0; y < table[i].length; y++) { //current table values
        if (tempTable[u][0] === (table[i])[y][0]) {
          tempTable[u][1] += (table[i])[y][1];
        } else {
          console.log("Not contained");
        }
      }
    }
  }
}
combineTable([
  [
    ['a', 1],
    ['b', 1]
  ],
  [
    ['a', 1]
  ]
])
Dylan Landry
  • 1,150
  • 11
  • 27
NRCme
  • 13
  • 1

2 Answers2

0

You need to use the Array.prototype.slice() method for each nested array.

So instead of var tempTable = table[0];, you need to use:

var tempTable = table[0].map(arr => arr.slice());

You can't just say thing = arr[0] for a multidimensional array because that just returns a reference to the value, not a copied value.

function combineTable(table) {
  var tempTable = table[0].map(arr => arr.slice()); // This is the line changed
  for (var i = 1; i < table.length; i++) { //each table
    for (var u = 0; u < tempTable.length; u++) { //temptable values
      for (var y = 0; y < table[i].length; y++) { //current table values
        if (tempTable[u][0] === (table[i])[y][0]) {
          tempTable[u][1] += (table[i])[y][1];
        } else {
          console.log("Not contained");
        }
      }
    }
  }
  // Adding console logging for demo
  console.log(table);
  console.log(tempTable);
}

combineTable([
  [
    ['a', 1],
    ['b', 1]
  ],
  [
    ['a', 1]
  ]
])
Samathingamajig
  • 11,839
  • 3
  • 12
  • 34
0

note: I wrote this answer because I thought the accepted answer didn't clearly answer your question of why modifying one array changed another.

Modifying array A also modifies array B if array A and B are references to the same array.

const arrayA = [1]
const arrayB = arrayA;
arrayB[0] = 2;
console.log(arrayA, arrayB); // -> [2]   [2]

JavaScript uses a call by sharing strategy for objects, which applies to arrays since in JavaScript an array is a type of object. How to mutate objects while avoiding side-effects such as mutating other objects depends on the kind of data within the array.

Because JavaScript uses pass by value for primitives, we can do the following:

const array2D = [[1]];
const array1D = [ array2D[0][0] ];
array1D[0] = 2;
console.log(array2D, array1D); // -> [[1]]   [2]

Though, if the array contains other arrays, then our problem is reproduced.

const array3D = [[[1]]];
const array2D = [ array3D[0][0] ];
array2D[0][0] = 2;
console.log(array3D, array2D) // -> [[[2]]]   [[2]]

Essentially, if you're mutating an object's property, be careful of what references exist to that that object. If I write JavaScript with this in mind, then I find I don't run into issues about this very often.

If you're in a serious bind, you can deep clone an object to produce a new object without any references. There's catches to this, here's an answer that shows how a deep clone function could be built and the problems with it: How to Deep clone in javascript

And lodash provides a utility for it _.cloneDeep()

Dylan Landry
  • 1,150
  • 11
  • 27