web-dev-qa-db-ja.com

Javascript:オブジェクトをある配列から別の配列に移動する:最良のアプローチ?

「objects」と「appliedObjects」という2つの配列があります。 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);
            }
        });
    }

しかし、その後、ループ配列から値が削除されると、インデックスごとに行われるため、他のすべての項目を追加または削除しないことに気付きました。

次に、追加または削除するアイテムのリストを保持するために一時配列を使用してみましたが、奇妙な参照の問題が発生し始めました。

私はこの問題に対する最善の解決策が何であるかについて少し話を始めています...どんな助けやガイダンスも大歓迎です。

14
morganpdx
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);
}
12
Artem

コンストラクトがあまりにも多く自動的に実行される場合(この場合は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++;
        }
    }
6
Ed Staub

さて、これは公平な答えではないかもしれませんが、複雑なオブジェクト/配列操作をたくさんしていることに気付いたら、実際にlodashまたはアンダースコアライブラリをチェックアウトする必要があります。次に、ライナーでこれを解決できます:

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

これは私があなたのために働くと思うものの最初のパスです。作業の正確性をテストできるようにテストページを作成中です。微調整した結果を更新します。

編集:私はそれを実行し、問題を正しく理解していればあなたが望んでいることをするようです。編集した構文エラーがいくつかありました。

簡潔でクリーンなコードを使用したプランクです 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));
        });
    };
0
tuckerjt07

単に配列全体を移動したい場合は、次のことができます。

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/

0
Zbyszek Swirski

繰り返しながら配列を変更すると、常にいくつかの要素が失われます。

その方法の1つは、3番目の配列を使用して、配列から削除する必要があるオブジェクトの参照を保存することです。

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