简体   繁体   中英

Shifting rows and columns in 2D arrays - Javascript

I have a situation as such:

var array = [
  [1,2,3],
  [4,5,6],
  [7,8,9]
]

And I am trying to create a function that shifts either a row or a column so the result would be:

shiftRow(array, 1) 

[
  [3,1,2],
  [4,5,6],
  [7,8,9]
]

shiftColumn(array,1)

[
  [7,2,3],
  [1,5,6],
  [4,8,9]
]

I want the first number to be the last number then continue from there in any instance. I have tried several nested for loops, and I'm quite stuck at figuring this out. Keep in mind I have only been coding for a few months though.

This is what I have so far. It gives me an undefined error at the end and it is moving it the wrong way.

function shiftRow(arr) {
  var temp = arr
  for(var i = 0; i < temp.length; i++) {
    for(var j = 0; j < temp[i].length; j++) {
      temp[i][j] = temp[i][j+1]
    }
  }
  return temp;
}

The previous answers looks ok, but lacks one major thing when dealing with array indexes ; validation checks.

You do not want to try to access non-existent array indexes. Therefore, I created a small class to shift your array as needed, with validation. This will throw an Error if either the row or column index is invalid.

class ArrayShifter {
    static showArray(array) {
        // console.log("Array : ", array);
        console.log('------');
        for (const [index, elem] of array.entries()) {
            console.log(''+elem);
        }
    }

    static validateRowIndex(array, rowIndex) {
        if (!isArray(array) || !isInt(rowIndex) || rowIndex <= 0 || rowIndex > array.length) {
            throw new Error('The row index is wrong');
        }
    }

    static validateColumnIndex(array, columnIndex) {
        if (!isArray(array) || !isInt(columnIndex) || columnIndex <= 0 || columnIndex > array[0].length) {
            throw new Error('The column index is wrong');
        }
    }

    static shiftRow(array, rowIndex) {
        ArrayShifter.validateRowIndex(array, rowIndex);
        array[rowIndex - 1].unshift(array[rowIndex - 1].pop());

        return array;
    }

    static shiftColumn(array, columnIndex) {
        ArrayShifter.validateColumnIndex(array, columnIndex);
        let prev = array[array.length - 1][columnIndex - 1];

        for (const elem of array) {
            let tmp = elem[columnIndex - 1];
            elem[columnIndex - 1] = prev;
            prev = tmp;
        }

        return array;
    }
}

let sourceArray1 = [
    [1,2,3],
    [4,5,6],
    [7,8,9],
];
let sourceArray2 = [
    [1,2,3],
    [4,5,6],
    [7,8,9],
];
let controlArrayShiftRow = [
    [3,1,2],
    [4,5,6],
    [7,8,9],
];
let controlArrayColumnRow = [
    [7,2,3],
    [1,5,6],
    [4,8,9],
];

// arrayShifter.showArray(sourceArray1);
console.log(`Shift row test is ${areArraysEqual(controlArrayShiftRow, ArrayShifter.shiftRow(sourceArray1, 1))}.`);

// arrayShifter.showArray(sourceArray2);
console.log(`Shift column test is ${areArraysEqual(controlArrayColumnRow, ArrayShifter.shiftColumn(sourceArray2, 1))}.`);




//-------------------- Unimportant js functions --------------------
function isArray(arr) {
    if (Object.prototype.toString.call([]) === '[object Array]') { //Make sure an array has a class attribute of [object Array]
        //Test passed, now check if is an Array
        return Array.isArray(arr) || (typeof arr === 'object' && Object.prototype.toString.call(arr) === '[object Array]');
    }
    else {
        throw new Exception('toString message changed for Object Array'); //Make sure the 'toString' output won't change in the futur (cf. http://stackoverflow.com/a/8365215)
    }
}
function isInt(n) {
    return typeof n === 'number' && parseFloat(n) === parseInt(n, 10) && !isNaN(n);
}
function areArraysEqual(a1, a2) {
    return JSON.stringify(a1) == JSON.stringify(a2);
}

The working code can be seen in this codepen .

For row shift you can use Array#unshift and Array#pop methods. And for shifting the column use a Array#forEach method with a temp variable.

 var array = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ], array1 = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] function shiftRow(arr, row) { arr[row - 1].unshift(arr[row - 1].pop()); return arr; } function shiftCol(arr, col) { var prev = arr[arr.length - 1][col-1]; arr.forEach(function(v) { var t = v[col - 1]; v[col - 1] = prev; prev = t; }) return arr; } console.log(shiftRow(array, 1)) console.log(shiftCol(array1, 1)) 

First, you have to pass two arguments: the array, and the row/column you want to shift. And remember that arrays are zero-based, not 1. So in your example, if you want to shit the first row, you need to pass 0, not 1.

Second, since you want to put the last element at the front, and push others down, you need to loop, for shiftRow , from back to front. Here's a solution. Feel free to improve on it.

function shiftRow(arr, row) {
  var temp = arr[row];
  var j=temp.length-1;
  var x=temp[j];
  for(var i = j; i > 0; i--) {
    temp[i]=temp[i-1];
  }
  temp[0]=x;
  arr[row]=temp;
}

As you can see it works only on the row you want to shift, and starts from the end, working its way to the front. Before the loop I save the last element (which will be overwritten) and put that in the first slot at the end of the loop.

Given this question :

Transposing a javascript array efficiently

It is sufficient to implement only shiftRow and transpose before and after it if we want to achieve shiftCol

function shiftRow(array,n)
{
  let retVal=[[]];
  for(i=0;i<array.length;i++)
  {
    if (i==n)
      retVal[i]= array[i].slice(1,array.length).concat(array[i][0]);
    else
      retVal[i]=array[i];
  }
  return retVal;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM