除了循环之外,删除 LinkedHashMap 中的前半部分条目

Removing the first half of the entries in LinkedHashMap other than looping

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

我的问题是,当地图有 n 个元素时,如果我想删除第一个 n/2 个元素,有没有比遍历 keys 并重复调用 [=17] 更好的方法=]?也就是像这样

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 只要我能:

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


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

但是,可能不直接支持删除一半密钥的特定用例。您宁愿找到删除键 below/above 特定值的方法,并获得 highest/lowest 键。

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

对于与您所做的等效的更简单的代码:

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

如果您不想为缓存集使用库,LinkedHashSet 的设计让您可以通过 subclassing 轻松构建自己的缓存集。例如,当您添加超过特定集合大小时的元素时,一个简单地删除最旧条目的基本方法:

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

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