Javascript: перемещение объектов из одного массива в другой: лучший подход?

У меня есть два массива, называемые "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);
            }
        });
    }

но потом я понял, что когда значение было удалено из массива цикла, и оно не добавит или не удалит каждый другой элемент, так как оно пошло по индексу.

затем я попробовал использовать временный массив для хранения списка элементов добавить или удалить, и я начал получать странные ссылочные проблемы.

Я начинаю немного вращаться над тем, какое лучшее решение этой проблемы было бы...любая помощь и / или руководство будут очень признательны.

6 ответов


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

когда конструкция делает слишком много автоматически (например, forEach или даже for-loop, в этом случае), используйте более примитивную конструкцию, которая позволяет вам ясно сказать, что должно произойти, без необходимости работать вокруг конструкции. Используя цикл 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++;
        }
    }

вы изменяете массив во время итерации по нему, вы всегда будете пропускать некоторые элементы.

один из способов сделать это - использовать третий массив для хранения ссылок на объекты, которые необходимо удалить из массива:

// "$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);
});

теперь это, возможно, не справедливый ответ, но если вы заметили, что делаете много сложных манипуляций с объектами/массивами, вы должны действительно проверить библиотеку lodash или underscore. тогда вы могли бы решить это с помощью on liner:

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

Это первый проход в том, что я думаю, будет работать для вас. Я в процессе создания тестовой страницы, чтобы я мог проверить точность работы и обновить измененный результат, которого, надеюсь, не будет.

EDIT: я запустил его, и он, похоже, делает то, что вы хотите, если я правильно понимаю проблему. Было несколько синтаксических ошибок, которые я отредактировал.

вот планка с конденсированным, очищенным кодом 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));
        });
    };

Если вы хотите переместить просто весь массив, вы можете сделать:

appliedObjects = objects;
objects = []

конечно, это не будет работать, если они были параметры функции! В противном случае я не вижу другого способа, кроме копирования в цикле, например

while (objects.length) {
    appliedObjects.push(objects[0]);
    objects.splice(0,1);
}

или если вам нравится короткий код :) :

while (objects.length) appliedObjects.push(objects.splice(0,1));

проверить скрипку http://jsfiddle.net/060ywajm/