Julius Doan
Julius Doan

Reputation: 356

Shifting array of elements into another index of the array

Not sure if this may be a duplicate, but I am having some troubles trying to think of the best way of shifting an element in an array filled of arrays of elements.

Such as:

var foo = [
    [ {obj: 1}, {obj: 2}, {obj: 3}, {obj: 4} ],
    [ {obj: 5}, {obj: 6}, {obj: 7}, {obj: 8} ], 
    [ {obj: 9}, {obj: 10}, {obj: 11}, {obj: 12} ]
];

If I remove one element given an arrayIndex, it would remove that element then shift all of the proceeding elements down to the appropriate array. Such as if I remove obj 3 the result would be:

var arrayIndex = 0;
var objIndex = 2;

var bar = foo[arrayIndex].splice(objIndex, 1);

Result:

bar = [
    [ {obj: 1}, {obj: 2}, {obj: 4}, {obj: 5} ],
    [ {obj: 6}, {obj: 7}, {obj: 8}, {obj: 9} ], 
    [ {obj: 10}, {obj: 11}, {obj: 12} ]
];

Another example would be as shown removing obj 8:

var arrayIndex = 1;
var objIndex = 3;

var bar = foo[arrayIndex].splice(objIndex, 1);

Result:

bar = [
    [ {obj: 1}, {obj: 2}, {obj: 3}, {obj: 4} ],
    [ {obj: 5}, {obj: 6}, {obj: 7}, {obj: 9} ], 
    [ {obj: 10}, {obj: 11}, {obj: 12} ]
];

The issue for me is shifting all of the proceeding elements into the correct array position. Additionally, I would like the empty array to be removed. Where foo's length would decrease. foo will also be mutated.

Here was my attempted jsfiddle: https://jsfiddle.net/mLw8kncn/1/

Any help would be appreciated.

Upvotes: 4

Views: 274

Answers (3)

Tommy
Tommy

Reputation: 3124

A simple way is to store your items in 1D array instead of 2D. Then manipulate the indexes.

var foo = [ {obj: 1}, {obj: 2}, {obj: 3}, {obj: 4},
    {obj: 5}, {obj: 6}, {obj: 7}, {obj: 8},
    {obj: 9}, {obj: 10}, {obj: 11}, {obj: 12} ];

function remove(arrayIndex, objIndex) {
    var realIndex = arrayIndex * 4 + objIndex;
    foo.splice(realIndex, 1);
}

Otherwise, you have to rearrange items after every splice.

function remove(arrayIndex, objIndex) {
    foo[arrayIndex].splice(objIndex, 1);

    for (var i = arrayIndex + 1; i < foo.length; i++) {
        var obj = foo[i].shift();
        foo[i - 1].push(obj);
    }

    if (foo[foo.length - 1].length <= 0) {
        foo.pop();
    }
}

And this is much complicated.

Upvotes: 3

Redu
Redu

Reputation: 26161

I guess Array.prototype.reduce() is ideal for this job. You may do it like

var        foo =  [[{obj: 1}, {obj: 2}, {obj: 3}, {obj: 4}],
                   [{obj: 5}, {obj: 6}, {obj: 7}, {obj: 8}], 
                   [{obj: 9}, {obj: 10}, {obj: 11}, {obj: 12}]
                  ],
removeAndShift = (a,ai,oi) => ai == a.length-1 ? a[ai].splice(oi,1)
                                               : a.reduce((p,c,i,a) => { if (i == ai+1) {
	                                                                    p.splice(oi,1);
	                                                                    p.push(c.shift());
                                                                         }
                                                                         i > ai+1 && p.push(c.shift());
                                                                         return c;
                                                                       });
 removeAndShift(foo,1,3);
 console.log(foo);

Note that we are not doing anything but simply splicing out the item to delete if the array item to remove an item from is at the very end.

Upvotes: 0

trincot
trincot

Reputation: 349974

You could use a function that flattens the array temporarily to 1 dimension (keeping record of the original sizes of the sub arrays), then applies the standard splice on that, and finally reconstructs the 2D array based on the recorded size information.

This will have as benefit you can use all the power of splice to delete more than one element at a time and/or insert other elements in the same operation.

The given index must therefore be the index as if the input array were 1-dimensional:

function splice2d(a, start, deleteCount /*, item1, item2, ...*/){
    var flat = [], sizes = [];
    // Make a flat array, keeping record of subarray sizes
    while (a.length) {
        sizes.push(a[0].length);
        flat = flat.concat(a.shift());
    };
    // Apply original splice to flat array
    [].splice.apply(flat, [].slice.call(arguments, 1));
    // Reconstruct 2D array again based on sizes
    while (sizes.length) {
        a.push(flat.splice(0, sizes.shift()));
    }
    return a;
}

// Sample data
var foo = 
    [[{obj: 1}, {obj: 2}, {obj: 3}, {obj: 4}],
    [{obj: 5}, {obj: 6}, {obj: 7}, {obj: 8}], 
    [{obj: 9}, {obj: 10}, {obj: 11}, {obj: 12}]]

// Mutate
splice2d(foo, 2, 1);
// Output result
console.log(foo);

Upvotes: 0

Related Questions