使用值数组选择所有元素的最有效方法

时间:2012-09-04 03:02:41

标签: javascript jquery

假设我有一个<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];

如何最有效地选择值为2和3的<option>

我正在使用拥有数千<select><option>的{​​{1}},因此这样做手动无效:

var optionElements = [];

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

这太慢了。有没有办法将jQuery的值列表交给我需要选择的元素?有什么想法吗?

P.S。如果您想知道,我正在优化目前jQuery PickList widgetsucks at handling large lists

9 个答案:

答案 0 :(得分: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] ] ];

}

答案 1 :(得分:2)

这还没有被描述过,所以用一个 grain 盐的振动器拿它:

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

我们显然可以做更多事情(比如缓存选定和未选中的值,以便我们可以避免每次用户在它们之间移动值时重建它们)如果我们假设数据都是唯一的,我们甚至可以将整个三分之二&#34;哈希&#34; - 但无论我们做什么we should profile it确保它确实和我们认为一样快。

答案 2 :(得分: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();
    }
}

答案 3 :(得分: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);
    } 
})

答案 4 :(得分:1)

首先,我要感谢大家的精彩回应!我正在考虑每个人,在做出决定之前我可能会做基准测试。

在此期间,我实际上找到了另一个问题的“可接受的”解决方案based on this answer

这就是我提出的(最后一个块,使用自定义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毫秒。

答案 5 :(得分: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');

这可能不是最快的解决方案,但它相当优化,非常简单,无需跟踪列表和所有爵士乐。它应该足够快你的情况。

答案 6 :(得分: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);

答案 7 :(得分:0)

让optionValues由一组索引选择。

for(var i = 0; i < optionValues.length; i++) {
  document.forms[0].foobar.options[optionValues[i]].selected = true;
}

答案 8 :(得分:0)

如果您只想按值选择,则以下内容应该合适。它只循环选项一次,不调用任何其他函数,只调用一个内置方法,因此它应该很快。

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

在某些浏览器中,循环遍历集合很慢,因此首先将选项集合转换为数组可能需要付费。但在测试之前测试可能不值得。

请注意,如果select不是多选,则只会选择带有最后列出值的选项。

如果您想允许其他各种字符或案例,您可能需要摆弄正则表达式。