Java 计数器哈希映射以删除较少的计数器值

Java 计数器哈希映射以删除较少的计数器值,java,collections,hashmap,Java,Collections,Hashmap,是否有任何HashMap实现是有界的,并且在达到限制时移除最小映射值 比如说, int size = 3; Map<Object, Integer> map = new HashMap<>(size); Object[] objects = {'a', 'a', 'a', 'b', 'c', 'c', 'd'}; for (Object o : objects) { if (map.containsKey(o)) {

是否有任何HashMap实现是有界的,并且在达到限制时移除最小映射值

比如说,

    int size = 3;
    Map<Object, Integer> map = new HashMap<>(size);
    Object[] objects = {'a', 'a', 'a', 'b', 'c', 'c', 'd'};
    for (Object o : objects) {
        if (map.containsKey(o)) {
            map.put(o, map.get(o) + 1);
        } else {
            map.put(o, 1);
        }
    }

顺序不一定要保留,请注意,b被删除,因为插入d时映射将满,并且具有最小值的条目被删除。

这听起来很少见,我认为您找不到这样的实现。根据您的用例,您可能会使用队列。

HashMap是一种映射,其目的是用值映射键。钥匙是独一无二的

例如,您可以将
整数滚动
映射到
学生
。为此,您可以使用HashMap

Map studentMap=newhashmap()

在您的情况下,您需要定义maxSize的容器。根据首选参数(访问最少或最旧的对象),如果当前大小等于定义的maxSize,并且需要插入新项目,则可以删除该项目。这更像是一个队列。您可以通过包装数组、LinedList、ArrayList等(根据您的实际需求)来实现自己的队列


仅仅因为HashMap可以接受2个通用参数,所以强制它作为问题的解决方案不是一个好主意。选择正确的数据结构,并可使用它创建自定义数据结构以解决此问题。

您可以使用
LinkedHashMap
实现此目的。通常情况下,您会将其用于LRU缓存,并且实现不是很有效,但这是一个
Map
,允许您限制其中的条目数量

new LinkedHashMap<Object, Integer>() {
    @Override
    protected boolean removeEldestEntry(Map.Entry<Object, Integer> eldest) {
        // Remove one of smallest values when going over 100
        if(size() > 100) {
            Optional<Map.Entry<Object, Integer>> min = this.entrySet().stream()
                        .min(Comparator.comparing(Map.Entry::getValue));

            min.ifPresent((k) -> remove(k.getKey()));
        }
        return false; // Always return false, so map doesn't remove entries
    }
};
newlinkedhashmap(){
@凌驾
受保护的布尔重构(Map.Entry最早){
//超过100时,删除其中一个最小值
如果(大小()>100){
可选最小值=this.entrySet().stream()
.min(Comparator.comparing(Map.Entry::getValue));
min.ifPresent((k)->移除(k.getKey());
}
return false;//始终返回false,因此map不会删除条目
}
};

我不知道频率表只包含最近添加的频率。MRU表将是关键字。你应该看看番石榴和其他图书馆

自己动手:

for (Object o : objects) {
    map.merge(o, 1, Integer::sum); // Update frequency
    if (map.size() > maxSize) {
       map.remove(map.entrySet().stream()
           .sorted(Comparators.compare(Map.Entry<Object, Integer>::getValue))
           .map(Map.Entry<Object, Integer>::getKey)
           .findFirst()
           .get());
    }
}
for(对象o:对象){
merge(o,1,Integer::sum);//更新频率
if(map.size()>maxSize){
remove(map.entrySet().stream())
.sorted(Comparators.compare(Map.Entry::getValue))
.map(map.Entry::getKey)
.findFirst()
.get());
}
}

这将接受1的溢出(在非并发上下文中),遍历所有条目(慢)并删除最小值的键。

您可以创建自己的实现映射

class MyHashMap<K> extends HashMap<K, Integer> {

private int maxSize;

public MyHashMap(int maxSize) {
    this.maxSize = maxSize;
}

@Override
public Integer put(K key, Integer value) {
    Integer v = super.put(key, value);

    if (maxSize < size()) {
        entrySet().stream()
                  .filter(entry -> !entry.getKey().equals(key))
                  .min(Comparator.comparing(Map.Entry::getValue))
                  .ifPresent(entry -> remove(entry.getKey()));
    }

    return v;
}
类MyHashMap扩展了HashMap{ 私有int-maxSize; 公共MyHashMap(int maxSize){ this.maxSize=maxSize; } @凌驾 公共整数put(K键,整数值){ 整数v=super.put(键,值); if(maxSize!entry.getKey().equals(key)) .min(Comparator.comparing(Map.Entry::getValue)) .ifPresent(entry->remove(entry.getKey()); } 返回v; }
你能给我们举个例子并澄清一下吗?注意地图没有排序,所以你到底想要什么?只是更新了问题,这样它也可以是
{a,3},{b,1},{d,1}
注意
{b,1}
否?如果你添加
{e,0}
{d,1}
还是
{e,0}
将被删除?这基本上是一个带边界的出现计数器。因此,较新的条目的值始终为
1
,这总是给最后一个条目一个可能被删除的出现。如果您想在插入之前删除映射中的最小值,请说明。我看到的问题是,每个键都会出现一次ve a value>1.
键集
永远不会更改,因为最小的值始终是最新添加的。@AxelH如果返回
true
将删除最旧的条目(即head)。这就是我们返回
false
的原因。抱歉,我混淆了我的术语。我的意思是,您可以删除添加的最后一个条目,因为这将在插入后执行。这可能需要将最后插入的项存储在变量中(覆盖
put
putAll
),以确保不选择它。(如果行为不是预期的)@AxelH的想法是删除具有最小值的键。而不是添加最后一个或第一个条目。在上面的代码中,大小只有在插入新条目后才会溢出,因此它的最大值为
1
,但这不是我在这里提出的优化类型(出于可读性目的)。该解决方案工作正常,但任何put操作都将花费我们O(n),这是无法负担的。@Aladdin您是否声称您的其他代码是如此的优化,以至于它会成为性能热点?考虑到您显示的代码,我很难相信这一点。
Comparators.compare(Map.Entry::getValue)
不编译,它应该是
Comparator.comparing(Map.Entry::getValue)
,但您可以使用更简单的
Map.Entry.comparingByValue()
。通常,很少需要使用方法引用指定显式类型,例如
.Map(Map.Entry::getKey)
很好用。@Holger当然,我把它留给别人回答就更好了
class MyHashMap<K> extends HashMap<K, Integer> {

private int maxSize;

public MyHashMap(int maxSize) {
    this.maxSize = maxSize;
}

@Override
public Integer put(K key, Integer value) {
    Integer v = super.put(key, value);

    if (maxSize < size()) {
        entrySet().stream()
                  .filter(entry -> !entry.getKey().equals(key))
                  .min(Comparator.comparing(Map.Entry::getValue))
                  .ifPresent(entry -> remove(entry.getKey()));
    }

    return v;
}