如果我想要一个固定大小 N 的数组用于缓存最新的 N 项目,那么一次限制 N 已达到,我必须删除最早的项目,同时添加最新项目。
注意:我不关心最新项目是否在数组的开头或结尾,只要项目按照添加顺序删除。
显而易见的方法是:
push()
和shift()
(以便cache[0]
包含最旧的项目)或unshift()
和pop()
(以便cache[0]
包含最新项目)基本理念:
var cache = [], limit = 10000;
function cacheItem( item ) {
// In case we want to do anything with the oldest item
// before it's gone forever.
var oldest = [];
cache.push( item );
// Use WHILE and >= instead of just IF in case the cache
// was altered by more than one item at some point.
while ( cache.length >= limit ) {
oldest.push( cache.shift() );
}
return oldest;
}
但是,我已经阅读了shift
和unshift
的内存问题,因为它们会改变数组的开头并移动其他所有内容,但不幸的是,一个必须使用这些方法来做到这一点!
Qs的:
的结论
在对数据结构做了一些更多的研究之后(我从来没有在其他语言中编程,所以如果它不是Javascript原生的,我可能还没有听说过它!)并在多个浏览器中进行一系列基准测试小型和大型数组以及大量的读/写,这是我发现的:
offset
)。如果您要使用此方法,我建议使用已创建的方法,例如this circular buffer on GitHub。我实际需要的是Least Recently Used (LRU) Map(使用双向链表)。现在,由于我没有在原始问题中指定我的额外要求,我仍然将Bergi的答案标记为该特定问题的最佳答案。但是,因为我需要知道缓存中是否已经存在某个值,如果是这样,将其标记为缓存中的最新项,我必须添加到循环缓冲区的add()
方法中的附加逻辑(主要是{ {1}})使它不比'pop / unpush'方法更有效。然而,在这些情况下,LRUMap的性能会使其他两种水中的水都爆炸!
总结一下:
indexOf()
- 目前表现糟糕,没有理由使用答案 0 :(得分:5)
如果我有一个缓存最近N个项目的数组,一旦达到限制N,我将不得不在添加最新项目时删除最旧项目。
您不希望复制数组中的内容,每次都需要O(n)
步。
相反,这是ring buffer的完美用例。只需保留列表的“开始”和“结束”的偏移量,然后使用该偏移量访问缓冲区并以其模数为其模数。
var cache = new Array(10000);
cache.offset = 0;
function cacheItem(item) {
cache[cache.offset++] = item;
cache.offset %= cache.length;
}
function cacheGet(i) { // backwards, 0 is most recent
return cache[(cache.offset - 1 - i + cache.length) % cache.length];
}
答案 1 :(得分:1)
您可以使用Array#copyWithin
。
copyWithin()
方法浅析将数组的一部分复制到同一数组中的另一个位置并返回它,而不修改其大小。<强>描述强>
copyWithin
的工作方式类似于C和C ++的memmove
,是一种用于移动Array
数据的高性能方法。这尤其适用于同名的TypedArray
方法。序列被复制并粘贴为一个操作;即使复制和粘贴区域重叠,粘贴的序列也将具有复制的值。
copyWithin
函数故意泛型,它不要求其值为Array
对象。
copyWithin
方法是一种可变方法。它不会改变this
的长度,但会在必要时更改其内容并创建新属性。
var array = [0, 1, 2, 3, 4, 5];
array.copyWithin(0, 1);
console.log(array);
答案 2 :(得分:1)
您需要splice
现有项并使用unshift
(作为最新项目)将其放在前面中。如果您的缓存中已存在项,那么您可以unshift
和pop
。
function cacheItem( item )
{
var index = cache.indexOf( item );
index != -1 ? cache.splice( index, 1 ) : cache.pop();
cache.unshift( item );
}
项必须是String
或Number
,否则您需要使用{{1}编写自己的indexOf
实现定位和对象(如果 item 是一个对象)。