如何基于我选择的某些条件在JavaScript中对数组进行部分排序?
给定数组
var tab = [
{html: 'This is a test'},
{html: 'Locked item', locked: true},
{html: 'Another item'},
{html: 'Another one'}
//and 100 more items...
];
第二项被称为"锁定",它应该在数组排序后保持在同一位置(第二位)
var tab = [
{html: 'Another item'},
{html: 'Locked item', locked: true},
{html: 'Another one'},
{html: 'This is a test'},
//and 100 more items...
];
这是我目前拥有的完整代码:
var tab = [
{html: 'This is a test'},
{html: 'Locked item', locked: true},
{html: 'Another item'},
{html: 'Another one'}
//and more items...
];
tab.sort(function(a,b){
var aVal = a.html.toLowerCase();
var bVal = b.html.toLowerCase();
if (aVal===bVal)
return 0;
else
return aVal < bVal ? -1 : 1;
//how to handle locked items?
});
//desire output
/*var tab = [
{html: 'Another item'},
{html: 'Locked item', locked: true},
{html: 'Another one'},
{html: 'This is a test'},
//and more items...
];*/
console.log(tab);
请参阅fiddle
答案 0 :(得分:2)
这部分有效:
tab.sort(function(a,b){
if(a.locked || b.locked)
return 0;
if (a.html < b.html)
return -1;
if (a.html > b.html)
return 1;
return 0;
});
唯一的问题是,由于sort
使用的排序算法的工作方式,它无法移动锁定项目后的第1项。但是,它会对您示例中的最后2个项目进行排序。
让它以你想要的方式工作的最好方法是从数组中提取锁定的元素,将它们的索引保存在变量中,对数组进行排序,然后再次重新插入元素。
答案 1 :(得分:2)
这里的问题是sort
用于线性排序,没有别的。在其范围之外使用它是不可靠的,因为浏览器可以对它的执行方式进行一些优化。
因此,您基本上必须对数组的一部分进行线性排序。你可以做的最好的事情是拉出锁定的元素,保持它们的索引,执行排序并将锁定的元素放回正确的位置。
var fixed = [], i;
for (i = tab.length; i--;) {
if (tab[i].locked) {
fixed.unshift({index: i, item: tab[i]});
tab.splice(i, 1);
}
}
tab.sort(...); // Perform your sort
for (i = 0; i < fixed.length; i++)
tab.splice(fixed[i].index, 0, fixed[i].item);
不要因为我执行了一个向后for
并使用不移动而不是推送这一事实而感到困惑:要保持正确的索引。
反向循环是因为当执行splice
时它会改变数组,所以应该相应地调整前向循环i
以便不跳过项目。但这也会使fixed
中记录的索引变得混乱。所以我们做了一个向后循环,并使用unshift
来保持fixed
按index
属性排序。
请记住splice
有点慢,因此对于较大的数组,您可能需要使用一些更优化的算法。如果阵列不超过几十个固定元素,我猜是可以的。
答案 2 :(得分:1)
可能可以进行优化,但删除所有锁定的项目并存储其初始位置,然后将它们添加回已排序的数组应该可以正常工作:
var tab = [
{html: 'This is a test'},
{html: 'Locked item', locked: true},
{html: 'Another item'},
{html: 'Another one'}
//and more items...
];
var stored = {}, newTab = [];
for(var i = 0, iLimit = tab.length; i < iLimit; i++) {
if(tab[i].locked) {
stored[i] = tab[i];
} else {
newTab.push(tab[i]);
}
}
newTab.sort(function(a,b){
var aVal = a.html.toLowerCase();
var bVal = b.html.toLowerCase();
if (aVal===bVal) {
return 0;
} else {
return aVal < bVal ? -1 : 1;
}
});
for(var indice in stored) {
newTab.splice(indice, 0, stored[indice]);
}
console.log(newTab);
答案 3 :(得分:0)
或者,您可以过滤掉所有锁定的项目,将它们放在一个单独的数组中,如下所示:
[
{ obj: ..., index: ...},
{ ... }
]
这会保留每个对象的索引。然后你可以在排序后把它们放进去。看起来有点麻烦。
请查看Array.prototype.filter进行过滤,但请注意,如果没有填充,它在IE8中不起作用。