繁体   English   中英

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

[英]Most efficient way to select all elements with an array of values

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

我正在使用具有数千个<option><select> ,所以这样手动操作不起作用:

var optionElements = [];

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

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

PS如果您想知道,我正在优化我的jQuery PickList小部件 ,目前很难处理大型列表

您是否考虑过在插件引导程序中创建一个大哈希表? 授予的值是唯一的:

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

}

这还没有被描述,所以用盐的 谷物 振动器:

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

显然我们可以做更多的事情(比如缓存选定和未选择的值,这样我们可以避免每次用户在它们之间移动值时重建它们)如果我们假设数据都是唯一的,我们甚至可以把整个事物变成三个“哈希” - 但无论我们做什么,我们都应该对其进行分析,确保它真的像我们想象的那样快。

假设值是唯一的,您可以采取一些快捷方式。 例如,一旦找到了值,就可以通过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();
    }
}

尝试这个:

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

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

在此期间,我实际上根据对另一个问题的答案找到了“可接受的”解决方案。

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

我会试试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');

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

尝试这个。

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

让optionValues由一组索引选择。

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

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

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不是多选,则仅选择具有最后列出的值的选项。

如果要允许其他各种字符或大小写,则可能需要使用正则表达式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM