结构为键值的map_在Java中增加Map值的最有效方法-只需搜索键一次

结构为键值的map

这个问题可能被认为太基础了,但是在论坛中经常被问到。 在本文中,我将讨论一种仅在Map ONCE中搜索键的方法。

让我们首先来看一个例子。 假设我正在使用Map创建一个字符串频率列表,其中每个键是一个正在计数的String ,值是一个Integer ,每次添加一个String都会递增。 实现它的一种直接方法是

int count = map.containsKey(string) ? map.get(string) : 0;
map.put(string, count + 1);

这段代码运行很慢,因为它在地图上包含三个潜在的昂贵操作,即containsKey()get()[put()](http://docs.oracle.com/javase/7/docs/ api / java / util / Map.html#put(K,V)) 。 每个都需要在地图中搜索关键字。 现在,让我们重构代码以获得更好的性能。

整数与MutableInteger与AtomicInteger

我们必须调用三个昂贵的操作的重要原因之一是使用Integer进行计数。 在Java中, Integer不可变的 。 这样可以防止我们在构造后修改整数值。 因此,要增加一个计数器,我们必须首先从映射中获取整数,然后通过添加一个整数来创建另一个新整数,然后将其放回映射中。

为了使计数器可变,有几种方法。 一种是简单地创建自己的MutableInteger ,就像我在下面显示的那样。

public class MutableInteger {

  private int val;

  public MutableInteger(int val) {
    this.val = val;
  }

  public int get() {
    return val;
  }

  public void set(int val) {
    this.val = val;
  }
}

另一种方法可能是在Java中使用AtomicInteger ,该方法用于原子增量计数器等应用程序中。 但是AtomicInteger的主要选择是如果您希望通过对整数进行操作来实现线程安全。 因此,它不能用作Integer的替代。 基于此,如果线程安全不是您项目的重要考虑因素,则我不建议您使用AtomicInteger

仅搜索一次密钥

使用MutableInteger之后 ,我们可以将上面的代码更改为

if (map.containsKey(string)) {
  MutableInteger count = map.get(string);
  count.set(count.get() + 1);
} else {
  map.put(string, new MutableInteger(1));
}

要么

MutableInteger count = map.get(string);
if (count != null) {
  count.set(count.get() + 1);
} else {
  map.put(string, new MutableInteger(1));
}

在最坏的情况下,如果之前没有看到密钥,则代码将搜索密钥两次:一次用于检索,一次用于设置。 它比上一个要好得多。 但是我们不应该立即满足并停止。 如果您在Java文档中选中了[Map.put()](http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#put(K,V))方法,您会发现此方法将返回the previous value associated with key 。 这意味着我们可以将检索和设置合并为一个。 但是,您可能想知道:如果不首先检索计数器,如何设置新计数器? 现在,我们终于可以触摸本文中最棘手的部分:我们可以简化一下零频率计数器的放置!

public int incrementCount(K key, int count) {
    MutableInteger tmpCount = new MutableInteger(0);
    MutableInteger oldCount = map.put(key, tmpCount);
    if (oldCount != null) {
      count += oldCount.get();
    }
    tmpCount.set(count);
    return count;
  }

另一个柜台

看起来将所有必要的操作放入一个类中将对将来的使用有所帮助。 因此,我创建了一个名为Counter的类并将其公开。 计数器定义一个集合,该集合对对象出现在集合中的次数进行计数。 假设您有一个包含{a, a, b, c}的Counter。 在“ a”上调用getCount()将返回2,而在keySet()上调用将返回{a, b, c} 。 此类的工作方式类似于Map ,但具有不同的方法,可以轻松获取/设置/增加对象的计数并使用该计数计算各种函数。 Counter构造函数和addAll()方法可用于复制另一个Counter的内容。 根据IntCounterAbstractMapBag修改Counter类。

Counter上的一些突出操作包括

  • crementCount()decrementCount() :将给定键的给定计数与当前计数相加/相减。 如果该键以前未出现过,则假定其计数为0,因此增量方法会将其计数设置为给定的数量。 减量会将其计数设置为-1。
  • getCount() :返回给定键的当前计数,如果以前没有看到过,则返回0。
  • keysAt()keysAbove()keysBelow() :返回其计数在给定阈值之上,之下或之下的一组键。 该集合可能包含0个元素,但不会为null。
  • argmin ()argmax() :找到并返回此Counter中具有最小/最大计数的密钥。 如果有几个最小/最大计数,则返回随机值。 如果此Counter为空,则返回null。


翻译自: https://www.javacodegeeks.com/2013/10/most-efficient-way-to-increment-a-map-value-in-java-only-search-the-key-once.html

结构为键值的map

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值