将数组中的元素移动到另一个索引处

4

我不确定这是否是一个重复问题,但我正在努力想出在填充有元素数组的数组中移动元素的最佳方法。

例如:

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

如果我根据数组下标删除一个元素,它将删除该元素,然后将所有后续元素向下移动到适当的数组位置。例如,如果我删除obj 3,则结果如下:
var arrayIndex = 0;
var objIndex = 2;

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

结果:

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

另一个例子是如下所示,删除 obj 8:
var arrayIndex = 1;
var objIndex = 3;

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

结果:

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

对我来说,问题在于将所有前置元素移动到正确的数组位置。此外,我希望删除空数组。其中foo的长度会减少。foo也将被改变。
这是我尝试过的jsfiddle: https://jsfiddle.net/mLw8kncn/1/ 任何帮助都将不胜感激。

如果你从数组中删除一个元素,它会自动移位,唯一不会发生这种情况的时候是当你实际使用 delete 时。Delete 会留下一个空间,所以数组的长度不会减少。如果你正在使用 splice,那就不应该有问题。 - zer00ne
我注意到你想把元素移到其他数组中,我会尝试回答这部分问题。 - zer00ne
请展示一下你目前的尝试。 - 1983
你还没有描述空数组的情况。 - 1983
谢谢。当数组变为空时,它们会从 foo 中删除,还是保留为空数组?结果是否应该是一个新数组,而 foo 保持不变,还是 foo 应该被改变? - 1983
显示剩余3条评论
3个回答

3

一种简单的方法是将您的项目存储在1D数组中而不是2D数组中,然后操作索引。

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

否则,每次剪接后都必须重新排列项目。
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();
    }
}

而这更加复杂。


0

您可以使用一个将数组暂时压缩为1维的函数(保留子数组的原始大小记录),然后在其上应用标准的splice,最后根据记录的大小信息重建2D数组。

这样做的好处是您可以利用splice的全部功能,一次删除多个元素和/或在同一操作中插入其他元素。

因此,给定的索引必须是作为输入数组为1维时的索引:

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


0

我想Array.prototype.reduce()非常适合这个任务。你可以像这样做

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

请注意,如果要从数组中删除项目的数组项位于末尾,则我们不会执行任何操作,只是简单地拼接出要删除的项目。

我认为在推送和移动之前需要检查 c.length,否则可能会将 null 推送到数组中。当然,除非 OP 想要这样做:问题没有完全说明。 - 1983
我不会说reduce是理想的:你仅仅为了副作用而使用它,返回值并没有太多意义。 - 1983
@FizzyTea 同意 c.length 可能是个问题,但就 reduce 而言...我必须说,将几个相邻的项作为前一个和当前项一起移动对于这种情况是理想的,而我正在利用 reduce 的这种能力。(p.push(c.shift());) 我本可以修改代码以返回与 OP 所需完全相同的值,但那样会更加晦涩难懂。我想这样挺好的。 - Redu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接