最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do I delete the first N items from an ES6 Map object without recreating the Map? - Stack Overflow

programmeradmin2浏览0评论

Say I want to delete the first 100 entries of a Map without recreating the map, and also do this in the most efficient way.

Let's say you have a 500 item ES6 Map Object:

let map = new Map(... 500 items)

Currently I do it like this:

const newCache = new Map(
  Array.from(map).slice(100)
)

map.clear()

map = newCache

But this recreates the Map.

The other way is to run over the first 100 keys:

Array.from(map.keys())
     .slice(0, 100)
     .forEach(key => map.delete(key))

But it looks inefficient.

Say I want to delete the first 100 entries of a Map without recreating the map, and also do this in the most efficient way.

Let's say you have a 500 item ES6 Map Object:

let map = new Map(... 500 items)

Currently I do it like this:

const newCache = new Map(
  Array.from(map).slice(100)
)

map.clear()

map = newCache

But this recreates the Map.

The other way is to run over the first 100 keys:

Array.from(map.keys())
     .slice(0, 100)
     .forEach(key => map.delete(key))

But it looks inefficient.

Share Improve this question edited Mar 20, 2018 at 7:56 GrayedFox 2,55329 silver badges46 bronze badges asked Aug 17, 2017 at 8:59 Vitali ZaidmanVitali Zaidman 9481 gold badge10 silver badges24 bronze badges 9
  • 3 What's wrong with that? – Barmar Commented Aug 17, 2017 at 9:00
  • edited the question: i'd want to keep the same object. I also wonder if this is the most efficient way. – Vitali Zaidman Commented Aug 17, 2017 at 9:02
  • Possible duplicate of How to get subarray from array? – Rajesh Commented Aug 17, 2017 at 9:03
  • No they don't @NinaScholz... – malifa Commented Aug 17, 2017 at 9:06
  • 1 Sounds like an XY problem to me. You're trying to mix direct (Map) and sequential ("first N items") access in one data structure. What's your use case? – georg Commented Aug 17, 2017 at 9:24
 |  Show 4 more comments

6 Answers 6

Reset to default 11

Get an array of the first 100 keys of the Map, then delete them.

var keys = Array.from(map.keys()).slice(0, 100);
keys.forEach(k => map.delete(k));

Or you can use a loop so you don't need to create an array to slice.

var i = 0;
for (var k of map.keys()) {
    if (i++ > 100) {
        break;
    }
    map.delete(k);
}

I created a jsperf test with your two methods and this loop. The loop is bar far the most efficient, 5 times faster than slicing the keys.

Based on your comment, you're buildng some kind of a LRU cache. You might consider a better data structure that just a Map. For example,

cache = { deque: Array, index: Map, offset: Int }

When you put element in the cache, you append it to the deque and store its position + offset in the index:

class Cache...

    put(obj) {
        this.deque.push(obj)
        pos = this.deque.length - 1
        this.index.set(key(obj),  pos + this.offset)
    }

When getting element, check it its index of positive

get(obj) {
    pos = this.index.get(key(obj)) - this.offset
    if pos >= 0
       return this.deque[pos]
    // cache miss....

Now, cleaning up the cache won't involve any loops

 clear(count) {
     this.deque.splice(0, count)
     this.offset += count
 }

On a general note, if you want something to be re-created, but need a persistent pointer to it in the same time, you can just wrap the private object into a public one and proxy (some of) private's methods:

class Cache
   this._map = new Map() // feel free to recreate this when needed


    get(x) { return this._map.get(x) }
    set(x, y) { return this._map.set(x, y) }

myCache = new Cache() // this can be saved somewhere else 

If your Map is very big, you may not want to pull all of the keys back just to find the first few. In that case, entries may be a better option.

let n = 2;
let map = new Map();

map.set('a', 1);
map.set('b', 2);
map.set('c', 3);
map.set('d', 4);
console.log(map) // Map(4) {'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4}

let iterator = map.entries();
for (let i = 0; i < n; i++) {
  let entry = iterator.next();
  let key = entry.value[0];
  map.delete(key);
}

console.log(map) // Map(2) {'c' => 3, 'd' => 4}

Example -

let mm = new Map();
mm.set('10', 'Rina');
mm.set('11', 'Sita');
mm.set('12', 'Gita');

Gives you the first element of Map -

let keys = mm.keys().next() // Gives you 10 -> Rina

mm.delete(keys.value) // Delete from the beginning

An one-by-one approach without creating an array of all the keys

const removeFirstItems = (n) => {
    if (map.size >= n) {
        const it = map.keys();
        for (let i = 0; i < n; i++) {
            map.delete(it.next().value);
        }
    }
}

Example:

// array of 105 items 
// using random keys to see that the order of the keys does not matter
const map = new Map();
for (let i = 0; i < 105; i++) {
    map.set(Math.random(), i);
}

removeFirstItems(100);

// the last added 5 items should remain - order of keys does not matter
console.log(Array.from(map.values()).join(',')); // 100,101,102,103,104

I needed the N latest elements from the map, maybe someone will find it useful:

function keepNNewestItems(map, n) {
    const elementsToRemoveCount = map.size - n;
    const keys = map.keys();
    for (let i = 0; i < elementsToRemoveCount; i++) {
        map.delete(keys.next().value);
    }
}

function removeNOldestItems(map, n) {
    const elementsToRemoveCount = Math.min(n, map.size);
    const keys = map.keys();
    for (let i = 0; i < elementsToRemoveCount; i++) {
        map.delete(keys.next().value);
    }
}


/* Demo */
const createMap = (length) => new Map(Array.from({ length }, (_, i) => [ Math.random(), i ]));
const printMap = (map) => `[ ${Array.from(map.values()).join(', ')} ]`;

const map1 = createMap(11);
console.log(printMap(map1));
keepNNewestItems(map1, 6);
console.log(`keep 6 newest: ${printMap(map1)}`);

console.log('-'.repeat(36));

const map2 = createMap(11);
console.log(printMap(map2));
removeNOldestItems(map2, 6);
console.log(`remove 6 oldest:  ${printMap(map2)}`);

发布评论

评论列表(0)

  1. 暂无评论