如何保持Javascript数组排序,而不对其进行排序
Posted
技术标签:
【中文标题】如何保持Javascript数组排序,而不对其进行排序【英文标题】:How to keep Javascript array sorted, without sorting it 【发布时间】:2013-12-19 13:23:19 【问题描述】:我有一个 Node.js 应用程序,我必须经常做以下事情: - 检查特定数组是否已经包含某些元素 - 如果元素确实存在,更新它 - 如果元素不存在,则将其推送到数组中,然后使用下划线 _.sortBy 对其进行排序
为了检查元素是否已经存在于数组中,我使用了这个二分查找函数: http://oli.me.uk/2013/06/08/searching-javascript-arrays-with-a-binary-search/
这样,当数组的大小变大时,排序就会越来越慢。 我假设数组大小可能会增长到每个用户最多 20 000 个项目。最终会有成千上万的用户。该数组按一个键排序,这是一个相当短的字符串。如果需要,可以将其转换为整数。
所以,我需要一种更好的方法来保持数组排序, 而不是每次将新元素推送到其上时对其进行排序。
所以,我的问题是,我应该/如何编辑我使用的二进制搜索算法,以使我能够 如果数组中尚不存在新元素,则获取应放置新元素的数组索引? 或者还有什么其他的可能性来实现这一点。当然,我可以使用某种循环,从头开始遍历数组,直到找到新元素的位置。
所有数据都存储在MongoDB中。
换句话说,我希望在每次推送新元素时保持数组排序而不对其进行排序。
【问题讨论】:
【参考方案1】:很容易修改这个binaryIndexOf
函数以在没有找到匹配项时返回下一个元素的索引:
function binaryFind(searchElement)
'use strict';
var minIndex = 0;
var maxIndex = this.length - 1;
var currentIndex;
var currentElement;
while (minIndex <= maxIndex)
currentIndex = (minIndex + maxIndex) / 2 | 0; // Binary hack. Faster than Math.floor
currentElement = this[currentIndex];
if (currentElement < searchElement)
minIndex = currentIndex + 1;
else if (currentElement > searchElement)
maxIndex = currentIndex - 1;
else
return // Modification
found: true,
index: currentIndex
;
return // Modification
found: false,
index: currentElement < searchElement ? currentIndex + 1 : currentIndex
;
所以,现在它返回如下对象:
found: false, index: 4
其中index
是找到的元素或下一个元素的索引。
所以,现在插入一个新元素将如下所示:
var res = binaryFind.call(arr, element);
if (!res.found) arr.splice(res.index, 0, element);
现在您可以将binaryFind
添加到Array.prototype
以及一些用于添加新元素的助手:
Array.prototype.binaryFind = binaryFind;
Array.prototype.addSorted = function(element)
var res = this.binaryFind(element);
if (!res.found) this.splice(res.index, 0, element);
【讨论】:
太棒了!非常感谢你((:这就是我所需要的! @Juha-MattiHurnasti 我编辑了我的答案几次,现在它是正确的。 我发现这很有用,但我相信它无法处理数组存在空值的情况。它只是认为它始终与搜索元素匹配。将第一个if
条件更改为 if (currentElement === null || currentElement < searchElement)
并将“未找到”返回索引更改为 index: (currentElement < searchElement || currentElement === null) ? currentIndex + 1 : currentIndex
似乎在我的简短测试中有效,并且具有比任何其他值更少处理空值的效果。
注意使用| 0. 它比 Math.floor() 快 - 见measurethat.net/Benchmarks/Show/953/0/…【参考方案2】:
如果您的数组已经排序并且您想要插入一个元素,为了保持它的排序,您需要将它插入到数组中的特定位置。幸运的是,数组有一个方法可以做到这一点: Array.prototype.splice
所以,一旦你得到你需要插入的索引(你应该通过对你的二分搜索进行简单的修改来获得),你可以这样做:
myArr.splice(myIndex,0,myObj);
// myArr your sorted array
// myIndex the index of the first item larger than the one you want to insert
// myObj the item you want to insert
编辑:您的二进制搜索代码的作者也有同样的想法:
因此,如果您想插入一个值并想知道应该在哪里插入 把它,你可以运行函数并使用返回的数字 将值拼接到数组中。 Source
【讨论】:
问题是找到添加它的索引。这就是我想问的问题。【参考方案3】:我知道这是一个老问题的答案,但是下面使用 javascripts array.splice() 非常简单。
function inOrder(arr, item)
/* Insert item into arr keeping low to high order */
let ix = 0;
while (ix < arr.length)
//console.log('ix',ix);
if (item < arr[ix]) break;
ix++;
//console.log(' insert:', item, 'at:',ix);
arr.splice(ix,0,item);
return arr
通过反转测试可以将顺序从高到低更改
【讨论】:
线性搜索无法随元素数量很好地扩展。以上是关于如何保持Javascript数组排序,而不对其进行排序的主要内容,如果未能解决你的问题,请参考以下文章
如何对多个 mysql foreach 数组进行排序并需要它们在 php 中保持一致?