2016-07-15 2 views
2

Я пытаюсь создать функцию javascript, которая сдвигает массив справа x единиц на все юниты. Он должен поддерживать размер массива одинаковым, и он должен вызывать unloadChunk для элементов, которые сбрасываются с многомерного массива. Вот моя текущая реализация:Каков наилучший способ переноса многомерного массива в Javascript?

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]; 
       } 
      } 
     } 
    } 
} 

Если у вас возникли проблемы с пониманием, что именно я хочу, функция сдвига делать, посмотрите на this fiddle и посмотрите на вывод HTML. Моя попытка создания функции сдвига работает, но для петель 10. Мой вопрос был, есть ли более эффективный, менее верный способ сделать это?

+0

Вам нравится поддерживать одинаковые размеры массивов? или просто добавить, двигаясь вправо, «нуль» впереди? –

+0

@NinaScholz Сохранение одинакового размера массивов важно, потому что в моем случае я заполняю все нулевые значения новыми значениями. Извините, что не упоминал об этом в сообщении, теперь я отредактирую это. – epitaque

ответ

0

Вы можете использовать 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); 
    }) 
} 
+0

Проблема с этим решением заключается в том, что он не может обрабатывать одновременное перемещение нескольких единиц. Чтобы сдвинуть правые два блока, вам нужно дважды вызвать shiftRight(). – epitaque

0

Если интерпретировать вопрос правильно, вы можете использовать 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);

1

Это предложение использует

  • Array#forEach: посещение каждого пункта

  • Array#map: возвращаемое значение для каждого элемента

  • Array#pop: удаление и вернуть последний элемент

  • Array#push: добавляет один или несколько элементов в конце

  • Array#shift: удаляет и вернуть первый элемент

  • Array#unshift: добавляет один или несколько элементов в начале

Для лучшего visibillity я заменил значение null с 1000, 2000, 3000 и 4000 ,

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);

0

он должен вызвать 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 это массив показателей (см. array destructuring)
  • массив: текущий массив/матрица. Не вмешивайтесь в это, пока оно меняется. Основная причина этого аргумента - проверить, какой массив вы сейчас обрабатываете.
+0

Извините! Я неправильно сформулировал это. Я снова отредактировал OP для правильного написания: он должен вызывать unloadChunk для элементов, которые сбрасываются с многомерного массива. Моя предыдущая реализация вызывала проблемы для меня, потому что по какой-то причине я думал, что элементы, которые получают значение null, отправляются из многомерного массива. Чтобы обеспечить некоторый фон, я использую это как диспетчер chunk для моей игры three.js, и по мере того, как игрок переходит в новые куски, он должен смещать массив кусков в противоположном направлении и генерировать новые куски, заполняя нулевые значения с помощью новые куски. – epitaque

Смежные вопросы