You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中按子串统计Guava Multiset元素累计数量的最优方法

最优统计Guava Multiset前缀子串累计数量的方案

嘿,这个问题我之前处理类似场景时也琢磨过,结合Guava Multiset的特性,其实有个高效又清晰的方案,比单纯用Streams或者普通forEach要靠谱得多,尤其是数据量大的时候。

核心思路

你的需求本质是为每个原始元素生成所有需要统计的前缀键(单个子串、两段式、三段式),然后累加每个键对应的Multiset元素计数。关键是要利用Multiset的entrySet()来避免重复处理相同元素——毕竟Multiset里同一个元素可能出现N次,直接遍历entry(元素+次数)比遍历每个元素要高效太多。

具体实现代码

假设你已经有了存储原始数据的Multiset<String> dataMultiset,可以这么搞:

import com.google.common.collect.AtomicLongMap;
import com.google.common.collect.Multiset;

// 初始化统计容器,Guava的AtomicLongMap自带原子累加,线程安全;单线程环境用HashMap也可以
AtomicLongMap<String> prefixCountMap = AtomicLongMap.create();

// 遍历Multiset的entrySet,每个entry对应一个唯一元素和它的出现次数
for (Multiset.Entry<String> entry : dataMultiset.entrySet()) {
    String element = entry.getElement();
    long elementCount = entry.getCount();
    String[] parts = element.split(":");
    
    // 跳过格式不符合的元素(确保是三段式)
    if (parts.length != 3) {
        // 这里可以加日志记录错误,或者根据需求处理
        continue;
    }
    
    // 生成单个子串键并累加计数
    String singlePart = parts[0];
    prefixCountMap.addAndGet(singlePart, elementCount);
    
    // 生成两段式键并累加计数
    String twoParts = String.format("%s:%s", parts[0], parts[1]);
    prefixCountMap.addAndGet(twoParts, elementCount);
    
    // 生成三段式键并累加计数
    prefixCountMap.addAndGet(element, elementCount);
}

// 如果你需要转为普通Map或者不可变Map(方便后续Gson序列化)
Map<String, Long> finalResult = prefixCountMap.asMap();
// 或者生成不可变版本,更安全
// ImmutableMap<String, Long> finalResult = ImmutableMap.copyOf(prefixCountMap.asMap());

为什么这是最优方案?

  • 效率拉满:遍历entrySet()的时间复杂度是O(M),M是Multiset中唯一元素的数量,而不是总元素数。如果某个元素出现1000次,这里只处理1次,比遍历所有1000个元素的Stream/forEach高效太多。
  • 代码清晰:逻辑直白,每个步骤都明确,后续维护起来也方便。
  • 线程安全可选:用AtomicLongMap可以直接支持多线程场景,如果是单线程,换成HashMap配合merge方法也很简单:
    Map<String, Long> prefixCountMap = new HashMap<>();
    // 在循环里替换成:
    prefixCountMap.merge(singlePart, elementCount, Long::sum);
    prefixCountMap.merge(twoParts, elementCount, Long::sum);
    prefixCountMap.merge(element, elementCount, Long::sum);
    

如果你偏好Streams风格(适合小数据量)

如果你的数据量不大,用Streams写也可以,但记住效率不如entrySet方案:

import java.util.stream.Collectors;
import java.util.stream.Stream;

Map<String, Long> prefixCountMap = dataMultiset.stream()
    .flatMap(element -> {
        String[] parts = element.split(":");
        if (parts.length != 3) {
            return Stream.empty();
        }
        // 生成所有需要统计的键
        return Stream.of(parts[0], parts[0] + ":" + parts[1], element);
    })
    .collect(Collectors.groupingBy(
        Function.identity(),
        Collectors.counting()
    ));

后续Gson序列化

统计完成后的Map<String, Long>可以直接用Gson转为JSON,完全满足你生成交互式图表数据的需求:

import com.google.gson.Gson;

Gson gson = new Gson();
String chartDataJson = gson.toJson(finalResult);

内容的提问来源于stack exchange,提问作者Gregory Alan Bolcer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:15:27