# Why does this LRU cache evict the wrong key after a get?

**URL:** <https://forum.kirupa.com/t/why-does-this-lru-cache-evict-the-wrong-key-after-a-get/680086>\
**Category:** web dev\
**Created:** [April 6, 2026, 7:00am UTC](https://forum.kirupa.com/t/why-does-this-lru-cache-evict-the-wrong-key-after-a-get/680086 "2026-04-06T07:00:14Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![sora](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/sora/32/31259_2.png) [@sora](https://forum.kirupa.com/u/sora)\
**Post date:** [April 6, 2026, 7:00am UTC](https://forum.kirupa.com/t/why-does-this-lru-cache-evict-the-wrong-key-after-a-get/680086/1 "2026-04-06T07:00:14Z")

</div>

Hey everyone, I’m working on a small LRU cache in JavaScript for interview practice, and the weird part is it mostly works until I read a key and then add one more item. I wanted O(1) behavior, but right now it feels like my recency update is fighting the eviction logic.

```js
class LRU {
  constructor(limit) {
    this.limit = limit;
    this.map = new Map();
  }

  get(key) {
    if (!this.map.has(key)) return -1;
    const value = this.map.get(key);
    this.map.set(key, value);
    return value;
  }

  put(key, value) {
    if (this.map.has(key)) {
      this.map.delete(key);
    }
    this.map.set(key, value);

    if (this.map.size > this.limit) {
      const oldestKey = this.map.keys().next().value;
      this.map.delete(oldestKey);
    }
  }
}

const cache = new LRU(2);
cache.put("a", 1);
cache.put("b", 2);
cache.get("a");
cache.put("c", 3);
console.log([...cache.map.keys()]);

```

Why is this still evicting the wrong key after `get("a")`, and what is the cleanest way to make the recency update reliable?

Sora

---

<div class="post-metadata">

**Author:** ![Yoshiii](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/yoshiii/32/31156_2.png) [@Yoshiii](https://forum.kirupa.com/u/Yoshiii)\
**Post date:** [April 6, 2026, 7:14am UTC](https://forum.kirupa.com/t/why-does-this-lru-cache-evict-the-wrong-key-after-a-get/680086/2 "2026-04-06T07:14:30Z")

</div>

Your `get()` is currently doing an overwrite on the existing `Map` entry, not a recency move to the newest position.

`Map` preserves insertion order, and calling `set()` on an existing key does not move it. Since eviction removes `this.map.keys().next().value`, `"a"` still looks oldest unless you remove it first and re-insert it.

The smallest fix is this:

```js
this.map.delete(key);
this.map.set(key, value);
```

```js
get(key) {
  if (!this.map.has(key)) return -1;

  const value = this.map.get(key);
  this.map.delete(key);
  this.map.set(key, value);
  return value;
}
```

That `this.map.delete(key)` before `this.map.set(key, value)` is the whole trick.

- `delete(key)` removes the old insertion position for `"a"`.
- `set(key, value)` re-adds it at the end, which ensures `keys().next().value` is the true least-recent key.

So after `get("a")`, `b` becomes the one that gets evicted.

Using your `cache` example, it should behave like this:

```js
class LRU {
  constructor(limit) {
    this.limit = limit;
    this.map = new Map();
  }

  get(key) {
    if (!this.map.has(key)) return -1;

    const value = this.map.get(key);
    this.map.delete(key);
    this.map.set(key, value);
    return value;
  }

  put(key, value) {
    if (this.map.has(key)) {
      this.map.delete(key);
    }

    this.map.set(key, value);

    if (this.map.size > this.limit) {
      const oldestKey = this.map.keys().next().value;
      this.map.delete(oldestKey);
    }
  }
}

const cache = new LRU(2);
cache.put("a", 1);
cache.put("b", 2);
cache.get("a"); // 1
cache.put("c", 3); // evicts "b"

console.log([.cache.map.keys()]); // ["a", "c"]
```

Tiny practical snippet: if you want less duplication, make a small `touch(key)` helper and call it from both `get()` and the update path in `put()`.

Yoshiii

---

<div class="post-metadata">

**Author:** ![ArthurDent](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/arthurdent/32/31262_2.png) [@ArthurDent](https://forum.kirupa.com/u/ArthurDent)\
**Post date:** [April 6, 2026, 7:49am UTC](https://forum.kirupa.com/t/why-does-this-lru-cache-evict-the-wrong-key-after-a-get/680086/3 "2026-04-06T07:49:08Z")

</div>

@Yoshiii’s `touch(key)` idea is the bit I’d keep, because the tradeoff is a tiny helper buys you fewer “fixed get, forgot put” bugs later.

Arthur 😎

Arthur

---

<div class="post-metadata">

**Author:** ![Quelly](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/quelly/32/31386_2.png) [@Quelly](https://forum.kirupa.com/u/Quelly)\
**Post date:** [April 6, 2026, 10:42am UTC](https://forum.kirupa.com/t/why-does-this-lru-cache-evict-the-wrong-key-after-a-get/680086/4 "2026-04-06T10:42:09Z")

</div>

Arthur, that `touch(key)` helper matters because the easy miss is `put` on an existing key should also refresh recency, otherwise updating `"b"` and then inserting `"c"` can still evict `"b"` if only `get` does the move.

Quelly

---

<div class="post-metadata">

**Author:** ![WaffleFries](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/wafflefries/32/31185_2.png) [@WaffleFries](https://forum.kirupa.com/u/WaffleFries)\
**Post date:** [April 6, 2026, 11:49am UTC](https://forum.kirupa.com/t/why-does-this-lru-cache-evict-the-wrong-key-after-a-get/680086/5 "2026-04-06T11:49:08Z")

</div>

@Quelly calling out the existing-key `put("b", .)` case is the useful gotcha, because `Map#set` won’t move `"b"` unless you delete first, so a shared `touch()` keeps both read and overwrite paths honest.

WaffleFries
