如何正确增加存储在HashBasedTable中的值?

时间:2014-11-14 12:09:59

标签: java collections guava

现在,我将一些数值存储为HashBasedTable的值。当我想改变它的数量时,我需要写一些类似的东西:

table.put("AS", "BS", table.get("AS", "BS") == null? 123: table.get("AS", "BS")+123);

在我的感知中看起来相当混乱......有没有其他方法可以正确处理它?我的意思是没有空检查,离开地图并再次放回去。 也许你可以建议任何其他数据类型而不是Guava表?

谢谢!

3 个答案:

答案 0 :(得分:3)

它大致采用Table界面的方式,虽然我使用firstNonNull(T, T)来避免调用get两次:

Table<String, String, Integer> table = HashBasedTable.create();
table.put("AS", "X", 2);
// with null check
table.put("AS", "BS", Objects.firstNonNull(table.get("AS", "BS"), 0) + 123);
System.out.println(table);
// prints: {AS={BS=123, X=2}}

另一方面,如果您真的不需要Table界面和/或计数对您来说更重要(并且数字不是负数),请考虑使用Map<String, Multiset<String>。获取多集时,空检查会更加痛苦,但添加元素会更容易(因为Multiset的功能):

Map<String, Multiset<String>> mapWithMultiset = new HashMap<>();
// create new multiset to be put as value
HashMultiset<String> x = HashMultiset.create();
x.add("X", 2);
mapWithMultiset.put("AS", x);

// this feels dirty
if (!mapWithMultiset.containsKey("AS")) {
  mapWithMultiset.put("AS", HashMultiset.<String>create());
}
mapWithMultiset.get("AS").add("BS", 123);

System.out.println(mapWithMultiset);
// prints: {AS=[BS x 123, X x 2]}

您似乎确实需要MultisetMultimap又名BagMultimap这样的内容:

  1. 在Guava中不存在
  2. 会为你节省肮脏的东西。
  3. 可能看起来像这样,虽然命名会变得棘手,但Map / Collection中使用put / add方法会让人感到困惑(显式免责声明:没有MultisetMultimap ):

    MultisetMultimap<String, String> multisetMultimap = HashMultisetMultimap.create();
    multisetMultimap.add("AS", "X", 2);
    multisetMultimap.add("AS", "BS", 123);
    
    System.out.println(mapWithMultiset);
    // should print: {AS=[BS x 123, X x 2]}
    

    (如果你对这个解决方案感兴趣,你应该使用new issue on Github。如果在谷歌内部的Guava中有一些类似的东西,也许一些Guava开发者可以回答。)< / p>

答案 1 :(得分:2)

我想到的是LoadingCache<StringPair, AtomicInteger>

关键是:

   public final class StringPair {
       private final String key1, key2;
       // + constructor, hashCode, equals
   }

我会这样创造......

 LoadingCache<StringPair, AtomicInteger> cache = CacheBuilder.newBuilder()
   .build(
       new CacheLoader<StringPair, AtomicInteger>() {
         public AtomicInteger load(StringPair key) {
           return new AtomicInteger(0);
         }
       });

...然后

 AtomicInteger value = cache.get(new StringPair("AB", "AB"));
 value.addAndGet(123);

cache.get(new StringPair("AB", "AB")).addAndGet(123)

在此模式中,您只进行一次查找,并且更新非常高效,因为它不必再次遍历地图。您并没有真正将缓存用作缓存,而只是加载地图。

只要您不需要仅使用第一个键访问地图,我认为这样就可以了。

答案 2 :(得分:1)

我不确定你到底在问什么。

但你可以像这样重构你的代码。

Integer val = table.get("AS", "BS");
val = val == null ? 123 : (val + 123);
table.put("AS", "BS", val);