Reputation: 93
I'm trying to create a javascript function that shifts an array right x units any up y units. It must keep the array size the same, and it must call unloadChunk for elements that are getting shifted off the multidimensional array. Here is my current implementation:
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];
}
}
}
}
}
If you're having trouble understanding exactly what I want the shift function to do, take a look at this fiddle and look at the html output. My attempt at creating the shift function works, but it has 10 for loops. My question was, is there a more efficient, less verbose way to do this?
Upvotes: 2
Views: 5368
Reputation: 12657
it must call unloadChunk for elements that should be set to null
it's not a good idea to mutate an Array, while you're iterating over the same Array. So change unloadChunk()
to not change chunks
, but return the new value.
in my case I'm filling all the null values with new values.
then why do you bother to insert the null
-values in the first place? why don't you just insert the new values?
//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;
}
and the code:
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()
and shift2d()
expect as the last argument an (optional) callback function that returns the new values.
For consistency reasons, I pass the same argument as Array.map and the others
null
, only there for consistency reasonsshift2d
this is an array of indices (take a look at array destructuring)Upvotes: 0
Reputation: 386756
This proposal uses
Array#forEach
: visit each item
Array#map
: return value for each item
Array#pop
: removes and return last element
Array#push
: adds one or more elements at the end
Array#shift
: removes and return first element
Array#unshift
: adds one or more elements at the beginning
For better visibillity, I replaced the null
value with 1000
, 2000
, 3000
and 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);
Upvotes: 3
Reputation: 1
If interpret Question correctly, you can use 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);
Upvotes: 0
Reputation: 17102
You can use pop()
, push()
, shift()
, unshift()
Array methods
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);
})
}
Upvotes: 0