如何统计Guava ListMultimap中每组值的出现次数?
统计Guava ListMultimap中值组的出现次数
你需要统计Multimap里每个键对应的两个字符串组成的组合的出现频率,之前用自定义Storage类配合Collections.frequency没得到正确结果,大概率是因为Storage类没有正确重写equals()和hashCode()方法——毕竟Java默认的对象相等判断是基于引用的,不是内容。下面给你两种可行的解决方案:
方案一:用Guava的ImmutablePair直接统计
既然你已经在使用Guava,直接用它的ImmutablePair来封装每个键对应的两个字符串,然后用Guava的Multiset(专门用来统计元素出现次数的集合)来统计频率,会非常方便:
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutablePair; import com.google.common.collect.ListMultimap; import com.google.common.collect.Multiset; import com.google.common.collect.HashMultiset; import java.util.List; public class MultimapStats { public static void main(String[] args) { // 模拟你的Multimap数据 ListMultimap<Integer, String> multimap = ArrayListMultimap.create(); multimap.put(1, "key"); multimap.put(1, "car"); multimap.put(2, "key"); multimap.put(2, "blue"); multimap.put(3, "key"); multimap.put(3, "car"); // 把每个key对应的两个字符串转成ImmutablePair,存入Multiset统计次数 Multiset<ImmutablePair<String, String>> pairMultiset = HashMultiset.create(); for (Integer key : multimap.keySet()) { // 匹配你的添加逻辑:每个key对应两个值 List<String> values = multimap.get(key); if (values.size() == 2) { ImmutablePair<String, String> pair = ImmutablePair.of(values.get(0), values.get(1)); pairMultiset.add(pair); } } // 输出统计结果 System.out.println("[key,car]出现次数:" + pairMultiset.count(ImmutablePair.of("key", "car"))); // 输出2 System.out.println("[key,blue]出现次数:" + pairMultiset.count(ImmutablePair.of("key", "blue"))); // 输出1 } }
方案二:修复自定义Storage类的equals和hashCode
如果你坚持用自己的Storage类,必须重写equals()和hashCode(),让Java能识别内容相同的对象。比如:
import java.util.Objects; class Storage { private String str1; private String str2; public Storage(String str1, String str2) { this.str1 = str1; this.str2 = str2; } // 重写equals,判断两个Storage的内容是否完全一致 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Storage storage = (Storage) o; return Objects.equals(str1, storage.str1) && Objects.equals(str2, storage.str2); } // 重写hashCode,基于两个字符串的哈希值生成,保证equals相等的对象hashCode也相等 @Override public int hashCode() { return Objects.hash(str1, str2); } }
修复后再用Collections.frequency或者普通HashMap统计就没问题了:
import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; public class StorageStats { public static void main(String[] args) { HashMap<Integer, Storage> map = new HashMap<>(); map.put(1, new Storage("key", "car")); map.put(2, new Storage("key", "blue")); map.put(3, new Storage("key", "car")); List<Storage> storageList = new ArrayList<>(map.values()); int carCount = Collections.frequency(storageList, new Storage("key", "car")); System.out.println(carCount); // 输出2 } }
为什么之前的方法失败?
Collections.frequency依赖对象的equals()方法来判断是否相等,Java默认的equals()是比较对象的内存地址,而不是内容。所以即使两个Storage对象的字符串内容一样,它们也是不同的对象,frequency自然会统计错误。重写equals和hashCode后,就能让Java正确识别内容相同的对象了。
内容的提问来源于stack exchange,提问作者booyah
相关产品推荐
相关产品推荐

