web-dev-qa-db-ja.com

forループのスプライスで配列から項目を削除します

一種のjQueryライブ検索を実装したい。ただし、サーバーに入力を送信する前に、3文字以下の配列内のすべての項目を削除したい(ドイツ語では、これらの単語は通常、検索の観点では無視できるため)["this", "is", "a", "test"]["this", "test"]

$(document).ready(function() {
var timer, searchInput;
$('#searchFAQ').keyup(function() {
    clearTimeout(timer);
    timer = setTimeout(function() {
        searchInput = $('#searchFAQ').val().match(/\w+/g);
        if(searchInput) {
            for (var elem in searchInput) {
                if (searchInput[elem].length < 4) {
                    //remove those entries
                    searchInput.splice(elem, 1);
                }
            }
            $('#output').text(searchInput);
            //ajax call here
        }
    }, 500);
});
});

私の問題は、forループですべてのアイテムが削除されないことです。たとえば、typ "this is a test" "is"が削除された場合、 "a"は残ります。 [〜#〜] jsfiddle [〜#〜]

スプライスで項目を削除すると配列のインデックスが変更されるため、問題はforループであると思います。

おそらく誰でも私を助けることができますか?

48
SirDerpington

解決策1

次のようなものを使用して、逆方向にループできます。

var searchInput, i;

searchInput = ["this", "is", "a", "test"];
i = searchInput.length;
while (i--) {
    if (searchInput[i].length < 4) {
        searchInput.splice(i, 1);
    }
}

DEMO:http://jsfiddle.net/KXMeR/

これは、配列を段階的に反復し、スプライスすると配列がその場で変更されるため、アイテムが「シフト」され、一部の反復がスキップされるためです。 whileまたはforループで逆方向にループすると、スプライシングする方向にループしないため、これが修正されます。


解決策2

同時に、通常、その場で変更する代わりに新しい配列を生成する方が高速です。以下に例を示します。

var searchInput, newSearchInput, i, j, cur;

searchInput = ["this", "is", "a", "test"];
newSearchInput = [];
for (i = 0, j = searchInput.length; i < j; i++) {
    cur = searchInput[i];
    if (cur.length > 3) {
        newSearchInput.Push(cur);
    }
}

newSearchInputには有効な長さのアイテムのみが含まれ、searchInputには元のアイテムがまだあります。

デモ:http://jsfiddle.net/RYAx2/


解決策3

上記の2番目のソリューションに加えて、同様の新しいArray.prototypeメソッドは、それをうまく処理するために利用できます:filter。以下に例を示します。

var searchInput, newSearchInput;

searchInput = ["this", "is", "a", "test"];
newSearchInput = searchInput.filter(function (value, index, array) {
    return (value.length > 3);
});

デモ:http://jsfiddle.net/qky7D/


参照:

131
Ian
var myArr = [0,1,2,3,4,5,6];

問題ステートメント:

myArr.splice(2,1);

  \\ [0, 1, 3, 4, 5, 6];

2番目の位置で3が移動し、長さが1減って問題が発生します。

解決策:単純な解決策は、スプライシング時に逆方向に反復することです。

var i = myArr.length;
while (i--) {
    // do your stuff
}
5

lodashライブラリがインストールされている場合、それらはあなたが検討したいと思うかもしれない甘い宝石を持っています。

関数は_。forEachRight(コレクションの要素を右から右に繰り返します)左)

以下に例を示します。

var searchInput = ["this", "is", "a", "test"];

_.forEachRight(searchInput, function(value, key) {

    if (value.length < 4) {
        searchInput.splice(key, 1);
    }
});
2
Clinton Dobbs

$。grep 関数を使用して配列をフィルタリングすることもできます。

var timer, searchInput;
$('#searchFAQ').keyup(function () {
    clearTimeout(timer);
    timer = setTimeout(function () {
        searchInput = $('#searchFAQ').val().split(/\s+/g); // match is okay too
        searchInput = $.grep(searchInput, function(el) {
            return el.length >= 4;
        });
        console.log(searchInput);
    }, 500);
});

http://jsfiddle.net/dfsq/4Wdp9/

1
dfsq