3

要素があるとしましょう<select>

<select id="foobar" name="foobar" multiple="multiple">
    <option value="1">Foobar 1</option>
    <option value="2">Foobar 2</option>
    <option value="3">Foobar 3</option>
</select>

そして、次のような値の配列があるとしましょう:

var optionValues = [2, 3];

<option>値が 2 と 3 の s を最も効率的に選択するにはどうすればよいですか?

<select>は何千もの<option>s を持つ で作業しているので、次のように手動で行うとうまくいきません:

var optionElements = [];

$("#foobar").children().each(function() {
    if($.inArray($(this).val(), optionValues)) {
        optionElements.push($(this));
    }
}

遅すぎるだけです。選択する必要がある要素の値のリストをjQueryに渡す方法はありますか? 何か案は?

PS ご参考までに、私はjQuery PickList ウィジェットを最適化しているところですが、現在、大きなリストの処理が苦手です。

4

9 に答える 9

3

プラグインのブートストラップで大きなハッシュテーブルを作成することを検討しましたか? 付与される値は一意です。

var options = {};

$('#foobar').children().each(function(){

    options[this.value] = this;

});

この方法で検索するのは簡単です - options[valueNeeded]

編集 - 検索optionValues:

var optionValues = [2, 3];

var results = [];

for(i=0; i<optionValues.length;i++){

    results.push[ options[ optionValues[i] ] ];

}
于 2012-09-04T03:25:43.733 に答える
2

これはプロファイリングされていないので、塩の穀物シェーカーで服用してください。

var options = $("some-select").children(),
    toFind = [2, 3],
    values = {},
    selectedValues = [],
    unSelectedValues = [];
// First, make a lookup table of selectable values
// O(1) beats O(n) any day
for (i=0, l=toFind.length; i++; i<l) {
    values[toFind[i]] = true;
}
// Avoid using more complicated constructs like `forEach` where speed is critical
for (i=0, l=options.length; i++; i<l) {
    // Avoid nasty edge cases since we need to support *all* possible values
    // See: http://www.devthought.com/2012/01/18/an-object-is-not-a-hash/
    if (values[options[i]] === true) {
        selectedValues.push(options[i]);
    }
    else {
        unSelectedValues.push(options[i]);
    }
}

明らかにできることは他にもあります (選択された値と選択されていない値をキャッシュして、ユーザーがそれらの間で値を移動するたびにそれらを再構築するのを避けることができます)。 「ハッシュ」-しかし、何をするにしても、それをプロファイリングして、実際に私たちが思っているほど高速であることを確認する必要があります.

于 2012-09-04T03:29:08.963 に答える
1

値が一意であると仮定すると、いくつかのショートカットを使用できます。たとえば、値を見つけたらsplice()、検索配列からその値を削除することで、その値の検索を停止できます。

ただし、これは究極の最適化であり、ソートO(n^2)に至るまでの道のりをたどります。O(n log n)

まず、オプションをループして配列を作成します。基本的には、NodeListを配列に変換するだけです。次に、sortオプションの値をフェッチするためのコールバックを含む配列。検索配列を並べ替えます。これで、「options」配列をループして、現在の最小の検索項目を探すことができます。

var optsNodeList = document.getElementById('foobar').options,
    optsArray = [], l = optsNodeList.length, i,
    searchArray = [2,3], matches = [], misses = [];
for( i=0; i<l; i++) optsArray[i] = optsNodeList[i];
optsArray.sort(function(a,b) {return a.value < b.value ? -1 : 1;});
searchArray.sort();
while(searchArray[0] && (i = optsArray.shift())) {
    while( i > searchArray[0]) {
        misses.push(searchArray.shift());
    }
    if( i == searchArray[0]) {
        matches.push(i);
        searchArray.shift();
    }
}
于 2012-09-04T03:11:00.470 に答える
1

これを試して:

var $found = [];
var notFound = [];
var $opt = $('#foobar option');
$.each(optionValues, function(i, v){
    var $this = $opt.filter('[value='+v+']');
    if ($this.length) {
       $elems.push($this)
    } else {
       notFound.push(v);
    } 
})
于 2012-09-04T03:13:56.900 に答える
1

次のような jQuery のfilter()メソッドを試してみます。

var matches = filter(function() {
    // Determine if "this" is a match and return true/false appropriately
});

// Do something with the matches
matches.addClass('foobar');

ここでは最速のソリューションではないかもしれませんが、かなり最適化されており、リストやそのようなジャズを追跡する必要がなく、非常にシンプルです。状況に応じて十分に高速である必要があります。

于 2013-04-14T23:31:35.393 に答える
1

まず、すばらしい回答をくださった皆さんに感謝します。私はそれぞれを検討しており、決定を下す前におそらくベンチマークを行うでしょう.

その間、別の質問に対するこの回答に基づいて、実際に「許容できる」解決策を見つけました。

これが私が思いついたものです(カスタムfilter()実装の最後のブロックは、魔法が起こる場所です):

var items = self.sourceList.children(".ui-selected");

var itemIds = [];
items.each(function()
{
    itemIds.push( this.value );
});

self.element.children().filter(function()
{
    return $.inArray(this.value, itemIds) != -1;
}).attr("selected", "selected");

これが皆さんが投稿したものと同じくらい効率的かどうかは疑問ですが、1500 項目のリストで「追加」ピックリスト操作時間が約 10 秒から 300 ミリ秒に短縮されました。

于 2012-09-04T03:48:22.667 に答える
0

インデックスの配列によってoptionValuesを選択します。

for(var i = 0; i < optionValues.length; i++) {
  document.forms[0].foobar.options[optionValues[i]].selected = true;
}
于 2012-09-04T04:19:38.750 に答える
0

これを試して。

var optionValues = [2, 3],
    elements = [],
    options = document.getElementById('foobar').options;

var i = 0;
do {
    var option = options[i];
    if(optionValues.indexOf(+option.value) != -1) {
        elements.push(option);
    }
} while(i++ < options.length - 1);
于 2012-09-04T03:21:16.410 に答える
0

値で選択したいだけなら、以下が適しているはずです。オプションを 1 回ループするだけで、他の関数は呼び出されません。組み込みメソッドは 1 つだけなので、高速です。

function selectMultiByValue(el, valuesArr) {

  var opts = el.options;
  var re = new RegExp('^(' + valuesArr.join('|') + ')$');

  // Select options
  for (var i=0, iLen=opts.length; i<iLen; i++) {
    opts[i].selected = re.test(opts[i].value);
  } 
}

一部のブラウザーでは、コレクションのループが遅いため、最初にオプション コレクションを配列に変換する必要がある場合があります。しかし、それを行う前にテストしてください。それは価値がないかもしれません。

選択が複数選択でない場合は、最後にリストされた値を持つオプションのみが選択されることに注意してください。

他のさまざまな文字やケースを許可したい場合は、正規表現をいじる必要があるかもしれません。

于 2012-09-04T05:32:54.120 に答える