在 Javascript 中移动多维数组的最佳方法是什么?

What is the best way to shift a multidimensional array in Javascript?

本文关键字:最佳 方法 是什么 数组 Javascript 移动      更新时间:2023-09-26

我正在尝试创建一个 javascript 函数,该函数将数组向右移动 x 单位,任何向上 y 个单位。它必须保持数组大小相同,并且必须为从多维数组中移出的元素调用 unloadChunk。这是我目前的实现:

function shift(x, y) {
    if (x > 0) {
        for (var i = 0; i < chunks.length; i++) {
            for (var j = chunks[i].length - 1; j >= 0; j--) {
                if(j + x > chunks[i].length - 1 && chunks[i][j]) {
                  unloadChunk(i, j);
                } 
                if (j < x) {
                    chunks[i][j] = null;
                }
                else {
                    chunks[i][j] = chunks[i][j - x];
                }
            }
        }
    }
    else if (x < 0) {
        for (var i = 0; i < chunks.length; i++) {
            for (var j = 0; j < chunks[i].length; j++) {
                if(j + x  < 0 && chunks[i][j]) {
                  unloadChunk(i, j);
                } 
                if (j - x >= chunks[i].length) {
                    chunks[i][j] = null;
                }
                else {
                    chunks[i][j] = chunks[i][j - x];
                }
            }
        }
    }
    if (y > 0) {
        for (var i = 0; i < chunks.length; i++) {
            if (i + y >= chunks.length) {
                for (var j = 0; j < chunks.length; j++) {
                  if(i - y < 0 && chunks[i][j]) {
                    unloadChunk(i, j);
                  }
                  chunks[i][j] = null;
                }
            }
            else {
                for (var j = 0; j < chunks.length; j++) {
                    if(i - y < 0 && chunks[i][j]) {
                      unloadChunk(i, j);
                    }
                    chunks[i][j] = chunks[i + y][j];
                }
            }
        }
    }
    else if (y < 0) {
        for (var i = chunks.length - 1; i >= 0; i--) {
            if (i + y < 0) {
                for (var j = 0; j < chunks.length; j++) {
                     if(i - y > chunks.length - 1 && chunks[i][j]) {
                       unloadChunk(i, j);
                     }
                    chunks[i][j] = null;
                }
            }
            else {
                for (var j = 0; j < chunks.length; j++) {
                     if(i - y > chunks.length - 1 && chunks[i][j]) {
                       unloadChunk(i, j);
                     }
                    chunks[i][j] = chunks[i + y][j];
                }
            }
        }
    }
}

如果您在理解我想要 shift 函数做什么时遇到困难,请查看此小提琴并查看 html 输出。我创建 shift 函数的尝试有效,但它有 10 个 for 循环。我的问题是,有没有更有效、更不冗长的方法?

此提案使用

  • Array#forEach : 访问每个项目

  • Array#map:每个项目的返回值

  • Array#pop:删除并返回最后一个元素

  • Array#push:在末尾添加一个或多个元素

  • Array#shift:删除并返回第一个元素

  • Array#unshift:在开头添加一个或多个元素

为了获得更好的可见性,我将null值替换为1000200030004000

function shift(x, y) {
    while (x > 0) {
        chunks.forEach(function (a) {
            a.pop();
            a.unshift(1000);
        });
        x--;
    }
    while (x < 0) {
        chunks.forEach(function (a) {
            a.shift();
            a.push(2000);
        });
        x++;
    }
    while (y > 0) {
        chunks.unshift(chunks.pop().map(function () { return 3000; }));
        y--;
    }
    while (y < 0) {
        chunks.push(chunks.shift().map(function () { return 4000; }));
        y++;
    }
}
function print(msg) {
    document.body.innerHTML += '<p>' + msg + '</p>';
}
function printarr(arr) {
    for (var i = 0; i < arr.length; i++) {
        print(JSON.stringify(arr[i]))
    }
}
var chunks = [[5, 3, 1], [9, 2, 5], [2, 3, 7]];
print("chunks: " + JSON.stringify(chunks));
shift(1, 0);
print("shifting right 1. chunks: "); printarr(chunks);
shift(-1, 0);
print("shifting left 1. chunks: "); printarr(chunks);
shift(0, 1);
print("shifting up 1. chunks: "); printarr(chunks);
shift(0, -1);
print("shifting down 1. chunks: "); printarr(chunks);

您可以使用 pop()push()shift()unshift() 数组方法

var chunks = [
  [5, 3, 1],
  [9, 2, 5],
  [2, 3, 7]
];
function shiftDown(){
  chuck.pop();
  chuck.unshift(Array(3));
}
function shiftUp(){
  chuck.shift();
  chuck.push(Array(3));
}
function shiftRight(){
  chuck.foreach(function(v){
    v.pop();
    v.unshift(null);
  })
}
function shiftLeft(){
  chuck.foreach(function(v){
    v.shift();
    v.push(null);
  })
}

如果正确解释问题,您可以使用Array.prototype.forEach()Array.prototype.splice()

var chunks = [[5, 3, 1], [9, 2, 5], [2, 3, 7]];
// `x`: Index at which to start changing array
// `y`: An integer indicating the number of old array elements to remove
function shift(arr, x, y, replacement) {
  arr.forEach(function(curr, index) {
    // The elements to add to the array, beginning at the start index.
    // start index: `x` 
    curr.splice(x, y, replacement) 
  });
  return arr
}
// e.g.,
shift(chunks, -1, 1, null);
console.log(chunks);

它必须为应设置为 null 的元素调用 unloadChunk

在迭代同一数组时改变数组不是一个好主意。所以更改unloadChunk()不更改chunks,但返回新值。

就我而言,我正在用新值填充所有空值。

那你为什么首先要费心插入null值呢?你为什么不直接插入新值呢?

//one-dimensional shift
function shift(arr, offset, callback){
    var i, j, len = arr.length;
    if(len && (offset |= 0)){
        typeof callback === "function" || (callback = function(v){return v});
        if(offset < 0){
            for(i=-offset,j=0; i<len;)arr[j++]=arr[i++];
            while(j<len)arr[j]=callback(null,j++,arr);
        }else if(offset){
            for(i=len-offset,j=len; i>0;)arr[--j]=arr[--i];
            for(i=0; i<j;++i)arr[i]=callback(null,i,arr);
        }
    }
    return arr;
}
//two dimensional shift
function shift2d(matrix, offsetX, offsetY, callback){
    var i, len = matrix.length, tmp, fn;
    offsetY |= 0;
    offsetX |= 0;
    if(len && matrix[0].length && (offsetY || offsetX)){
        typeof callback === "function" || (callback = function(v){return v});
        fn = function(val,j){ return callback(null, [i,j], matrix) };
        tmp = {length: matrix[0].length};
        offsetY && shift(matrix, offsetY, function(){return tmp});
        for(i = 0; i < len; ++i){
            if(matrix[i] === tmp){
                matrix[i] = Array.from(tmp,fn);
            }else{
                shift(matrix[i], offsetX, fn);
            }
        }
    }
    return matrix;
}

和代码:

var chunks = [[5, 3, 1], [9, 2, 5], [2, 3, 7]];
console.log(chunks);
console.log(shift2d(chunks, -1, 1));
console.log(shift2d(chunks, 1, -1, computeValue));
function computeValue(value, index, array){
    console.log("value: %o index: %o, is chunks: %o", value, index, array === chunks);
    //return the new value for this field
    return JSON.stringify(index);
    return Math.random();
    //with ES6 array destructuring:
    var [row,col] = index;
    return row*3 + col;
}

shift()shift2d()期望返回新值的(可选)回调函数作为最后一个参数。出于一致性原因,我传递了与 Array.map 和其他参数相同的参数

  • :始终null,仅出于一致性原因
    而存在
  • 索引
  • :访问的"索引"。对于shift2d,这是一个索引数组(看看数组解构)
  • 数组
  • :当前数组/矩阵。不要在它被改变时弄乱这个。传递此参数的主要原因是检查您当前正在处理的数组。