[英]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.