JavaScript:数组排序优化
我有一个带有嵌套对象的JavaScript数组,例如:JavaScript:数组排序优化,javascript,arrays,sorting,Javascript,Arrays,Sorting,我有一个带有嵌套对象的JavaScript数组,例如:[{id:1,position:1},{id:2,position:2},{id:3,position:3},{id:4,position:4},{id:7,position:7},{id:5,position:5},{id:6,position 6}]。这只是一个例子,实际上我的应用程序中有一个数组,有100条记录。我试图用JavaScript数组排序方法对数组进行排序。假设数组名为myArray,那么我将执行以下操作: myArray.s
[{id:1,position:1},{id:2,position:2},{id:3,position:3},{id:4,position:4},{id:7,position:7},{id:5,position:5},{id:6,position 6}]
。这只是一个例子,实际上我的应用程序中有一个数组,有100条记录。我试图用JavaScript数组排序方法对数组进行排序。假设数组名为myArray,那么我将执行以下操作:
myArray.sort(function(a, b) {
return a.position- b.position;
});
它工作正常,但冻结了我的浏览器。有没有什么好的优化方法来进行排序。您可以自己实现像快速排序和合并排序这样非常高效的排序算法
您可以找到javascript sort()和MergeSort实现之间的比较。我建议你多读一些,找到一个更适合你的问题 在您稍后的一条评论中,您提到数据是一点一点地来的,而不是一次全部来的。但是
Array.prototype.sort()
每次都必须对整个数组进行返工,即使它大部分已经排序;只有少数元素超出了它们应该位于的位置
对于像您这样的情况,我倾向于使用插入排序,而不是JavaScript的内置排序方法(通常是合并排序或快速排序的变体,具体取决于引擎)插入排序作为通用排序算法不是很好,但当您只需要向已排序的数组中添加两个项目时,插入排序就很好了。这就是您在这里要做的,所以听起来很适合
下面是该算法的基本实现
/**
* Compare two items as though they were strings.
*
* This is like the default comparison for Array.prototype.sort()
*
* @param {*} a The first item
* @param {*} b The second item
*
* @return -1 if a is less, 1 is b is less, 0 otherwise
*/
function compareStrings(a, b) {
var sa = String(a),
sb = String(b);
if (sa < sb) {
return -1;
}
if (sa > sb) {
return 1;
}
return 0;
}
/**
* Insert a new item into a sorted array.
*
* The compareFunction callback function works as for the analogous argument
* in Array.prototype.sort(). Leave unspecified to compare lexically.
*
* @param {Array} data A sorted array, into which to put this item
* @param {*} newItem The item to add to the data.
* @param {Function=} compareFunction Optional comparison function.
*/
function arrayInsert(data, newItem, compareFunction) {
var stop = data.length,
i = 0;
compareFunction = compareFunction || compareStrings;
while (i < stop) {
if (compareFunction(newItem, data[i]) < 0) {
data.splice(i, 0, newItem);
return;
}
i += 1;
}
// If we got this far, then this should be the last item.
data.push(newItem);
}
/**
*将两个项目作为字符串进行比较。
*
*这类似于Array.prototype.sort()的默认比较
*
*@param{*}a是第一项
*@param{*}b第二项
*
*@return-1如果a小于,则1表示b小于,否则为0
*/
功能比较(a、b){
var sa=字符串(a),
sb=字符串(b);
if(sasb){
返回1;
}
返回0;
}
/**
*将新项插入已排序的数组中。
*
*compareFunction回调函数的作用与类似参数相同
*在Array.prototype.sort()中。保留未指定项以便在词汇上进行比较。
*
*@param{Array}data排序后的数组,将此项放入其中
*@param{*}newItem要添加到数据中的项。
*@param{Function=}compareFunction可选的比较函数。
*/
函数arrayInsert(数据、新项、比较函数){
var stop=data.length,
i=0;
compareFunction=compareFunction | | compareStrings;
当(我<停止){
if(compareFunction(newItem,data[i])<0){
数据拼接(i,0,新项);
返回;
}
i+=1;
}
//如果我们走到这一步,那么这应该是最后一项了。
数据推送(newItem);
}
当页面加载时,整个数组仍然需要排序一次,您不应该使用插入排序(最好让服务器向您发送已排序的数据,但如果您不能这样做,则使用普通的array.prototype.sort
函数)。然后,当您获得新数据时,为您获得的每个新数据项调用一次arrayInsert(data,newItem,/*您的比较函数*/)
。这应该会加快速度
如果这仍然太慢,那么您可以将新数据项放入队列,并在页面中添加一个短计时器。此计时器每隔几毫秒检查一次队列,如果有任何项目等待,它会将其中一个项目添加到数组中。这实际上不会使事情变得更快(事实上,它会使事情变得更慢),但页面不应该再冻结。我建议使用二进制搜索来定义插入新对象的索引,而不是先推后排序 以下代码没有开销,因为没有函数调用 还有一个变量
iteration
,它只能作为见证,您可以将其丢弃
我对以下代码进行了分析
假设您的a
已排序并且包含唯一的位置,则可以执行此操作
// THIS SECTION IS ONLY THERE TO SUIT YOUR CONSTRAINTS (100 objects in a)
var a = [];
for (var i = 0; i < 200; i++) {
if (i & 1) {
a.push({ id: i, position: i }); // objects are pushed only if they position is odd
}
}
// this means o.position (our new object) can have any even value, we know that it won't already exist in a
var o = {
id: 2,
position: 2
};
var start = 0,
end = (a.length - 1),
mid = end >>> 1,
left,
right;
var iterations = 0;
while (mid !== a.length - 1) {
if (mid > 0) {
leftIsMore = a[mid - 1].position > o.position;
} else {
leftIsMore = false;
}
rightIsLess = a[mid].position < o.position;
if (!leftIsMore && !rightIsLess) {
break;
} else if (leftIsMore) {
end = mid - 1;
} else {
start = mid + 1;
}
mid = (start + end) >>> 1;
iterations++;
}
var index = mid;
if (index === a.length - 1) {
a.push(o);
} else {
a.splice(index, 0, o);
}
console.log(a, 'Number of iterations to insert: ', iterations);
//此部分仅用于满足您的约束(一个区域中有100个对象)
var a=[];
对于(变量i=0;i<200;i++){
如果(i&1){
a、 push({id:i,position:i});//仅当对象的位置为奇数时才推送它们
}
}
//这意味着o.position(我们的新对象)可以有任何偶数值,我们知道它不会已经存在于
变量o={
id:2,
职位:2
};
var start=0,
结束=(a.长度-1),
mid=结束>>>1,
左边
正确的;
var迭代次数=0;
while(mid!==a.length-1){
如果(中间>0){
leftIsMore=a[mid-1]。位置>o位置;
}否则{
leftIsMore=false;
}
无右=a[中间]。位置>>1;
迭代++;
}
var指数=mid;
如果(索引===a.length-1){
a、 推(o);
}否则{
a、 拼接(指数0,o);
}
log(a,‘要插入的迭代次数:’,迭代次数);
如果冻结只是因为您没有使用排序
方法,请尝试以下操作:
myArray.sort(function(a, b) {
return a.position- b.position > 0 ? 1 : -1;
});
每个浏览器都会出现这种情况吗?您是如何确定这是导致冻结的原因的?如果它正在工作,但冻结了浏览器,您必须使用
setTimeout()
部分设置它(由于单线程)。这些数据是否来自某种请求?如果是这样,在传输数据之前让服务器对数据进行排序可能会更好。尝试将其添加到setTimeout(sortFunction(){…},0)
。要预测新位置,我还需要循环现有位置