【问题标题】:Removing the first half of the entries in LinkedHashMap other than looping删除 LinkedHashMap 中的前半部分条目而不是循环
【发布时间】:2021-10-15 22:23:59
【问题描述】:

我打算使用Hashtable,但一些现有答案只说LinkedHashMap 保留插入顺序。所以,看来我可以通过entrieskeys 属性获得插入顺序。

我的问题是,当地图有 n 个元素时,如果我想删除前 n/2 个元素,有没有比循环遍历 keys 并反复调用 remove(key) 更好的方法?也就是这样的

val a = LinkedHashMap<Int, Int>();
val n = 10;
for(i in 1 .. n)
{
    a[i] = i*10;
}
a.removeRange(0,n/2);

而不是

val a = LinkedHashMap<Int, Int>();
val n = 10;
for(i in 1 .. n)
{
    a[i] = i*10;
}

var i = 0;
var keysToRemove= ArrayList<Int>();
for(k in a.keys)
{
    if(i >= n/2)
        break;
    else
        i++

    keysToRemove.add(k);
}

for(k in keysToRemove)
{
    a.remove(k);
}

这样做的目的是我将地图用作缓存,当缓存已满时,我想清除最旧的一半条目。只要可以,我就不必使用LinkedHashMap

  • 使用键高效查找值。
  • 一次删除一系列条目。

【问题讨论】:

  • 为什么不使用 LRUCache?它会自动清除最近最少使用的条目。那里有很多实现,所以你不需要编码。

标签: dictionary kotlin linkedhashmap


【解决方案1】:

类中没有使这成为可能的方法。源代码对键或条目的范围没有任何操作。由于链接是建立在 HashMap 逻辑之上的,因此仍然必须通过散列键查找单独找到各个条目才能删除它们,因此在 LinkedHashMap 中无法更快地删除范围,这与LinkedList 与 ArrayList 的类比。

对于与您正在执行的操作等效的更简单的代码:

a.keys.take(a.size / 2).forEach(a::remove)

如果您不想将库用于缓存集,LinkedHashSet 旨在让您可以通过子类轻松构建自己的库。例如,当您添加超过某个集合大小的元素时,它会简单地删除最旧的条目:

class CacheHashMap<K, V>(private var maxSize: Int): LinkedHashMap<K, V>() {
    override fun removeEldestEntry(eldest: MutableMap.MutableEntry<K, V>?): Boolean =
        size == maxSize
}

此外,如果您在构造函数调用中将 accessOrder 设置为 true,它会按照最后使用的条目排序,这可能比插入顺序更适合您的情况。

【讨论】:

    【解决方案2】:

    编辑:抱歉,我错过了将其用作 LRU 缓存的部分,对于该用例,TreeMap 将不适合。


    如果插入顺序对您来说只是偶然的,而您想要的实际上是可比较键的实际顺序,您应该改用 TreeMap

    但是,可能不直接支持删除一半键的特定用例。您宁愿找到方法来删除低于/高于某个值的键,并获取最高/最低键。

    【讨论】:

    • 不,TreeMap 不保留插入顺序。
    • @k314159 这不是插入顺序,而是键的自然顺序,是的。我会添加精度。
    猜你喜欢
    • 1970-01-01
    • 2017-05-26
    • 2019-07-10
    • 2017-05-20
    • 1970-01-01
    • 2021-01-05
    • 1970-01-01
    • 2021-12-25
    相关资源
    最近更新 更多