JavaScript:将对象从一个数组移动到另一个数组:最佳方法?

17

我有两个数组,分别叫做“objects”和“appliedObjects”。我正在尝试使用JavaScript和/或Angular找到一种优雅的方法将对象从一个数组移动到另一个数组。

最初我做了以下操作:

   $scope.remove = function () {
        angular.forEach($scope.appliedObjects, function (element, index) {
            if (element.selected) {
                element.selected = false;
                $scope.objects.push(element);
                $scope.appliedObjects.splice(index, 1);
            }
        });
    }

   $scope.add= function () {
        angular.forEach($scope.objects, function (element, index) {
            if (element.selected) {
                element.selected = false;
                $scope.appliedObjects.push(element);
                $scope.objects.splice(index, 1);
            }
        });
    }

但后来我意识到,当从循环数组中移除该值时,它不会添加或删除任何其他项,因为它是按索引进行的。

然后,我尝试使用临时数组来存储要添加或删除的项目列表,但我开始遇到奇怪的引用问题。

我开始在这个问题上有些纠结了......非常感谢任何帮助和/或指导。


1
如果objects和appliedObjects是数组,则forEach回调函数中的参数应为function (element, index) {...},或者在您的情况下element可以是对象。 - micnil
1
@micnil 谢谢,我会更新代码。 - morganpdx
1
键是对象的值还是索引?如果不是,那么对象是否有一个唯一标识符属性? - tuckerjt07
1
@tuckerjt07 我刚刚更新了它...将“key”更改为“index”。实际上,它是数组的索引。 - morganpdx
1
没有唯一标识属性?如果有的话,我认为我有一个可行的解决方案。 - tuckerjt07
@tuckerjt07 元素内有一个唯一的ID属性,是的。 - morganpdx
8个回答

14
function moveElements(source, target, moveCheck) {
    for (var i = 0; i < source.length; i++) {
        var element = source[i];
        if (moveCheck(element)) {
            source.splice(i, 1);
            target.push(element);
            i--;
        }
    } 
}

function selectionMoveCheck(element) {
   if (element.selected) {
       element.selected = false;
       return true;
   }
}

$scope.remove = function () {
    moveElements($scope.appliedObjects, $scope.objects, selectionMoveCheck);
}

$scope.add = function () {
    moveElements($scope.objects, $scope.appliedObjects, selectionMoveCheck);
}

1
你能解释一下selectionMoveCheck参数吗? - morganpdx
1
@morganpdx,这是一个回调函数,应该返回true以移动元素。 - Artem
1
哦,我现在看到了...但函数名里不是有个打字错误吗?应该是moveCheck(element),对吧? - morganpdx
1
moveCheckmoveElements 的一个参数,selectionMoveCheck 是传递的特定函数。当然,您可以删除 moveCheck 并直接调用 selectionMoveCheck。我添加了该参数以增加灵活性。 - Artem
1
我移除了moveCheck参数,直接使用selectionMoveCheck,并且使它正常工作了...谢谢! - morganpdx

8

当一个构造体自动执行太多操作时(比如在这种情况下的forEach或者甚至for循环),使用更原始的构造体,可以让你清楚地表达应该发生什么,而不需要绕过构造体进行操作。使用while循环,你可以清晰地表达需要发生什么,而不必采取备份或其他方法进行操作:

function moveSelected(src, dest)  {
    var i = 0;
    while ( i < src.length ) {
        var item = src[i];
        if (item.selected) {
            src.splice(i,1);
            dest.push(item);
        }
        else i++;
    }
}

2
如果您想移动整个数组,您可以这样做:
appliedObjects = objects;
objects = []

当然,如果它们是函数的参数,它是不起作用的!否则,我看不到除了在循环中复制之外的其他方法,例如:
while (objects.length) {
    appliedObjects.push(objects[0]);
    objects.splice(0,1);
}

或者如果您喜欢简短的代码 :) :
while (objects.length) appliedObjects.push(objects.splice(0,1));

check fiddle http://jsfiddle.net/060ywajm/


2
你在迭代数组时改变了它,这样你总会错过一些元素。
一种解决方法是使用第三个数组来存储需要从数组中删除的对象的引用:
// "$scope.add" case
var objectsToRemove = [];

$scope.objects.forEach(function (value) {
  if (value.selected) {
    value.selected = false;
    $scope.appliedObjects.push(value);
    objectsToRemove.push(value);
  }
});

objectsToRemove.forEach(function (value) {
  $scope.objects.splice($scope.objects.indexOf(value), 1);
});

1
我尝试过,但开始出现引用错误;每个对象都有一个复选框,当我尝试使用临时存储数组时,由于某种原因,相同的对象存在于两个数组中,当您单击其中一个旁边的复选框时,另一个也会被选中。非常奇怪。 - morganpdx
1
我会再试一次,不过使用你的解决方案,看看效果如何。 - morganpdx
1
是的,同样的问题。它将其添加到新数组中,但不会从原始数组中删除它,在显示中,如果您单击添加的复选框旁边的复选框,则原始复选框也会被选中。 - morganpdx

0
你可以使用这个来连接两个数组:
let array3 = [...array1, ...array2];

0

你可以使用这个一行代码多次将arr1中的项目移动到arr2中,只需准备好检查函数即可。

arr2.push(arr1.splice(arr1.findIndex(arr1El => check(arr1El)),1)[0])

0

现在这可能不是一个公平的答案,但如果你注意到你正在进行很多复杂的对象/数组操作,你应该真正检查一下lodash或underscore库。然后你可以用一行代码解决这个问题:

//lodash remove function
appliedObjects.push.apply( appliedObjects, _.remove(objects, { 'selected': true}));

//or if you want to insert in the beginning of the list:
appliedObjects.splice(0, 0, _.remove(objects, { 'selected': true}));

1
了解有哪些库可以让我的生活更轻松总是很好的 :D - morganpdx

0

这是我认为适合你的初步尝试。我正在制作一个测试页面,以便测试工作的准确性,并将更新微调后的结果,希望不会有问题。

编辑:我运行了它,如果我正确理解问题,它似乎做到了你想要的。我已经编辑掉了一些语法错误。

这是压缩、清理过的代码的链接 http://plnkr.co/edit/K7XuMu?p=preview

HTML

<button ng-click="transferArrays(objects, appliedObjects)">Add</button>
<button ng-click="transferArrays(appliedObjects, objects)">Remove</button>

JS

$scope.transferArrays = function (arrayFrom, arrayTo) {
var selectedElements;
selectedElements = [];
angular.forEach(arrayFrom, function(element) {
  if (element.isSelected) {
    element.isSelected = false;
    selectedElements.push(element);
  }
});
angular.forEach(selectedElements, function(element) {
  arrayTo.push(arrayFrom.splice(
    arrayFrom.map(function(x) {
      return x.uniqueId;
    })
    .indexOf(element.uniqueId), 1));
});
};

旧代码

$scope.remove = function () {
        var selectedElements;
        selectedElements = [];
        angular.forEach($scope.appliedObjects, function (element) {
            if (element.isSelected) {
                element.isSelected = false;
                selectedElements.push(element);
            }
        });
        angular.forEach(selectedElements, function (element) {
            $scope.objects.push($scope.appliedObjects.splice(
                $scope.appliedObjects.map(function  (x) { return x.uniqueId; })
                .indexOf(element.uniqueId), 1));
        });
    };

$scope.add = function () {
        var selectedElements;
        selectedElements = [];
        angular.forEach($scope.objects, function (element) {
            if (element.isSelected) {
                element.isSelected = false;
                selectedElements.push(element);
            }
        });
        angular.forEach(selectedElements, function (element) {
            $scope.appliedObjects.push($scope.objects.splice(
                $scope.objects.map(function  (x) { return x.uniqueId; })
                .indexOf(element.uniqueId), 1));
        });
    };

在indexOf行的末尾缺少几个括号。到目前为止它还没有起作用...selectedElements数组似乎没有得到更新。 - morganpdx
我正在处理一个 Plunkr,但总是遇到一些问题。等我搞定了会发帖的。 - tuckerjt07
@ morganpdx 这是一个可用的 plunk,但我可能对您的数据做出了错误的假设 http://plnkr.co/edit/K7XuMu?p=preview - tuckerjt07
太酷了!我稍后会去看看。 - morganpdx

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