Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
Java Stream 高效分组计数并获取Top N元素_创想鸟

Java Stream 高效分组计数并获取Top N元素

Java Stream 高效分组计数并获取Top N元素

本文深入探讨了如何利用java stream api对数据进行高效的分组计数,并从中提取出现频率最高的top n元素。文章首先介绍了一种简洁的基于全排序的实现方式,该方法适用于数据集较小或top n值接近总数的情况。随后,针对大数据量和小型top n场景下的性能瓶颈,文章详细阐述了如何通过自定义`collector`结合`priorityqueue`(最小堆)进行部分排序,以显著提升处理效率,并提供了完整的代码示例及详细的实现原理。

Java Stream API为集合数据的处理提供了强大而富有表达力的工具。在实际开发中,我们经常会遇到需要对数据进行分组统计,并找出其中频率最高(或最低)的Top N元素的需求。例如,统计全球城市数据中,拥有城市数量最多的Top 3国家。本文将介绍两种实现这一目标的Stream方法,并分析它们的适用场景和性能特点。

方法一:基于全排序的简洁实现

这种方法的核心思想是:首先利用Collectors.groupingBy对数据进行分组,并通过Collectors.counting()计算每个分组的元素数量。这将生成一个Map,其中键K是分组字段,值Long是对应的计数。然后,将这个Map的entrySet转换为Stream,并根据值(计数)进行降序排序,最后通过limit()操作获取前N个元素,并提取其键。

示例代码

假设我们有一个City实体类,包含countryCode字段,我们希望找出拥有城市数量最多的Top N个国家代码:

import java.util.List;import java.util.Map;import java.util.stream.Collectors;// 假设 City 类定义如下class City {    private int id;    private String name;    private String countryCode;    public City(int id, String name, String countryCode) {        this.id = id;        this.name = name;        this.countryCode = countryCode;    }    public String getCountryCode() {        return countryCode;    }    @Override    public String toString() {        return "City{" + "id=" + id + ", name='" + name + ''' + ", countryCode='" + countryCode + ''' + '}';    }}public class StreamTopNMethods {    /**     * 使用全排序获取 Top N 国家代码     * @param cities 城市列表     * @param limit 需要获取的 Top N 数量     * @return Top N 国家代码列表     */    public static List getTopNCodesByFullSort(List cities, int limit) {        return cities.stream()            .collect(Collectors.groupingBy( // 1. 按 countryCode 分组并计数                City::getCountryCode,                Collectors.counting()            )) // 结果为 Map,例如 {DE=4, FR=2, DK=1, NO=1}            .entrySet().stream() // 2. 获取 Map 的 entrySet 并转换为 Stream            .sorted(Map.Entry.comparingByValue().reversed()) // 3. 按计数降序排序            .limit(limit) // 4. 取前 limit 个元素            .map(Map.Entry::getKey) // 5. 提取国家代码 (键)            .toList(); // 6. 收集结果到 List    }    public static void main(String[] args) {        List cityList = List.of(            new City(1, "Berlin", "DE"),            new City(2, "Munich", "DE"),            new City(3, "Köln", "DE"),            new City(4, "Paris", "FR"),            new City(5, "Kopenhag", "DK"),            new City(6, "Hamburg", "DE"),            new City(7, "Lyon", "FR"),            new City(8, "Oslo", "NO"),            new City(9, "Frankfurt", "DE")        );        List top3Countries = getTopNCodesByFullSort(cityList, 3);        System.out.println("Top 3 Countries by city count (Full Sort): " + top3Countries);        // 示例输出: Top 3 Countries by city count (Full Sort): [DE, FR, DK] (或 [DE, FR, NO],取决于DK和NO在Map中的相对顺序,因为它们的计数相同)    }}

性能分析与注意事项

这种方法的优点是代码简洁、易于理解。然而,它的时间复杂度为 O(M log M),其中 M 是分组后得到的唯一键的数量。这是因为 sorted() 操作会对整个 entrySet 进行排序。当原始数据集非常庞大,导致 M 很大,而我们只需要获取少数几个Top N元素时(即 limit 远小于 M),这种全局排序的开销会比较大,效率较低。

立即学习“Java免费学习笔记(深入)”;

方法二:利用自定义 Collector 和 PriorityQueue 进行部分排序

为了优化上述方法的性能瓶颈,我们可以采用一种更高效的策略:利用最小堆(PriorityQueue)实现部分排序。这种方法避免了对所有分组结果进行完全排序,而是在遍历过程中动态维护一个包含Top N元素的堆。当数据集庞大且 N 值相对较小时,这种方法能显著提升性能。

核心思想

首先,与方法一相同,我们通过Collectors.groupingBy得到 Map。然后,我们创建一个自定义的Collector,其内部使用一个大小为 N 的 PriorityQueue。这个PriorityQueue被配置为一个最小堆,用于存储当前遍历到的Top N元素。每当处理一个新的Map entry时,我们将其值(计数)与堆中最小元素的值进行比较:如果新元素的值更大,则移除堆中最小元素,并添加新元素。

泛化方法与自定义 Collector 实现

为了代码的复用性,我们可以将获取Top N的逻辑泛化。

import java.util.Comparator;import java.util.List;import java.util.Map;import java.util.PriorityQueue;import java.util.Queue;import java.util.function.Function;import java.util.stream.Collector;import java.util.stream.Collectors;// ... City 类定义同上public class StreamTopNMethodsAdvanced {    /**     * 泛化方法:使用自定义 Collector 和 PriorityQueue 获取 Top N 元素     * @param list 原始数据列表     * @param keyExtractor 用于从原始数据中提取分组键的函数     * @param limit 需要获取的 Top N 数量     * @param  原始数据类型     * @param  分组键类型     * @return Top N 键的列表     */    public static  List getTopNByPriorityQueue(List list,                                                         Function keyExtractor,                                                         int limit) {        return list.stream()            .collect(Collectors.groupingBy( // 1. 按 keyExtractor 提取的键分组并计数                keyExtractor,                Collectors.counting()            )) // 结果为 Map            .entrySet().stream() // 2. 获取 Map 的 entrySet 并转换为 Stream            .collect(getMaxNCollector( // 3. 使用自定义 Collector 获取 Top N                limit,                Map.Entry.comparingByValue().reversed(), // 比较器,用于 PriorityQueue 维护最小堆                Map.Entry::getKey // 提取最终结果的函数            ));    }    /**     * 辅助方法:向 PriorityQueue 中尝试添加元素     * 确保队列始终只包含 'size' 个元素,且这些元素是当前遍历过所有元素中“最大”的 'size' 个。     * @param queue PriorityQueue 实例     * @param next 待添加的下一个元素     * @param comparator 用于比较元素的比较器     * @param size 队列的最大容量 (即 N 值)     * @param  队列中元素的类型     */    public static  void tryAdd(Queue queue, T next, Comparator comparator, int size) {        // 如果队列已满,且新元素比队列中“最小”的元素(即堆顶元素)“更大”(根据比较器)        // 注意:这里的 comparator 是 reversed 的,所以 compare(queue.element(), next) < 0 意味着 next 更大        if (queue.size() == size && comparator.compare(queue.element(), next) < 0) {            queue.remove(); // 移除堆顶元素(当前 Top N 中最小的那个)        }        // 如果队列未满,或者新元素被认为“更大”并已移除旧元素,则添加新元素        if (queue.size() < size) {            queue.add(next);        }    }    /**     * 自定义 Collector,用于从 Stream 中获取 Top N 元素。     * @param size 需要获取的 Top N 数量     * @param comparator 用于在 PriorityQueue 中排序元素的比较器。     *                   如果需要 Top N 最大值,此比较器应使得“较小”的元素排在前面(即为最小堆)。     *                   对于 Map.Entry 场景,若要获取计数最大的 N 个,则比较器应为 Map.Entry.comparingByValue()。     *                   但由于 PriorityQueue 默认是最小堆,为了让“最大”的元素留在堆中,我们传入一个“反向”的比较器。     *                   例如,`Map.Entry.comparingByValue().reversed()`,这样计数小的元素会在堆顶。     * @param keyExtractor 用于从堆中的元素(Map.Entry)提取最终结果(键)的函数     * @param  Stream 中元素的类型 (这里是 Map.Entry<K, Long

以上就是Java Stream 高效分组计数并获取Top N元素的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/205354.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
mysql安装后如何优化配置文件
上一篇 2026年9月21日 08:29:17
c++如何使用gRPC构建微服务_c++高性能RPC框架实战
下一篇 2025年12月19日 10:27:17

相关推荐

  • mysql安装后如何优化配置文件

    答案:优化MySQL配置需先定位配置文件,再根据硬件和业务调整内存、InnoDB、连接等核心参数。具体包括设置innodb_buffer_pool_size为物理内存50%~70%,合理配置日志参数与连接数,启用慢查询日志,并使用工具辅助调优,避免过度配置,确保稳定高效。 MySQL 安装后,优化配…

    2026年9月21日
    000
  • Linux怎么列出系统中已安装的deb包

    使用dpkg -l或apt list –installed可列出已安装的.deb包,前者结合grep ^ii过滤已安装项,后者输出更清晰,两者均支持重定向保存到文件。 在Linux系统中,特别是基于Debian的发行版(如Ubuntu),可以使用命令行工具列出已安装的.deb包。最常用的…

    2026年9月21日
    000
  • mac怎么阻止特定app访问网络_Mac阻止应用访问网络方法

    可通过系统防火墙、hosts文件、第三方工具或pf防火墙阻止应用联网。首先,macOS内置防火墙可阻断入站连接,需在“系统设置-网络-防火墙”中添加应用并启用阻止;其次,编辑/etc/hosts文件,将目标域名指向127.0.0.1可屏蔽其网络访问,需刷新DNS缓存生效;再者,使用Little Sn…

    2026年9月21日
    000
  • VSCode的括号匹配功能如何自定义?

    可通过 settings.json 自定义括号高亮的边框和背景色;2. 用 editor.matchBrackets 控制是否启用高亮;3. 启用 bracketPairColorization 可为嵌套括号着色;4. 使用 Ctrl/Cmd + Shift + 快速跳转配对括号。 VSCode 的…

    2026年9月21日
    000
  • 马斯克xAI的Grok将推AI视频检测工具,能否破解深度伪造难题?

    随着ai视频生成技术飞速渗透网络,深度伪造内容不断扩散,网络信息真实性面临前所未有的挑战。在此背景下,马斯克的xai公司的grok模型即将推出一项关键升级,打造一款“真伪侦探”工具。 近日,马斯克在X平台回应网友担忧时表示,Grok即将获得识别AI生成视频并追踪其网络来源的能力,以此应对深度伪造内容…

    2026年9月21日
    000
  • JSF应用中Markdown文档动态链接处理指南

    本教程旨在解决jsf web应用程序中集成markdown文档时,如何动态处理内部链接以实现页面局部更新的问题。通过结合服务器端markdown渲染和客户端javascript事件监听,我们可以拦截markdown生成的html链接点击事件,利用ajax异步加载并渲染目标markdown文件,从而在…

    2026年9月21日
    500
  • AI推文助手如何生成节日祝福 AI推文助手的情感连接内容创作

    AI推文助手如何生成节日祝福 AI推文助手的情感连接内容创作AI推文助手如何生成节日祝福 AI推文助手的情感连接内容创作AI推文助手如何生成节日祝福 AI推文助手的情感连接内容创作AI推文助手如何生成节日祝福 AI推文助手的情感连接内容创作

    答案:通过AI推文助手的节日模板、情感关键词、用户数据定制和多语言混合策略,可高效生成个性化祝福,增强受众情感连接。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 如果您希望借助AI推文助手在节日期间传递温暖的祝福,同时增强与受众的情感连接…

    2026年9月21日 用户投稿
    000
  • 如何通过命令行参数启动VSCode?

    掌握VSCode命令行用法可提升开发效率,需先安装code命令到PATH,之后可用code .打开目录、code 文件名打开文件、code –diff比较文件、–disable-extensions排查问题,并支持别名与Shell结合使用。 通过命令行启动 VSCode 是一…

    2026年9月21日
    100
  • 如何基于Swoole开发自定义框架?

    基于swoole开发自定义框架可以通过以下步骤实现:1. 创建核心app类,初始化swoole服务器并定义回调函数;2. 实现路由功能,使用router类处理请求分发;3. 添加中间件支持,使用middleware类处理请求;4. 集成异步数据库操作,使用swoole的mysql协程客户端;5. 实…

    2026年9月21日
    000
  • Linux如何使用dnf安装软件包

    dnf是Fedora、CentOS Stream和RHEL 8+的默认包管理工具,用于安装、更新、删除软件包。1. 安装单个包:sudo dnf install package_name,如htop;2. 安装多个包:sudo dnf install vim curl;3. 从本地.rpm文件安装:…

    2026年9月21日
    000
  • 什么是抖音?– 2024 年您需要了解的一切

    抖音究竟是什么? 抖音是一款专注于短视频分享的社交平台,最初以对口型功能起家,在 Musical.ly 时期广为人知。如今,它已发展成为全球最具影响力的社交媒体之一,用户不仅能创作娱乐内容,还能参与教育、时尚、科技等多元领域的表达与传播。尽管起源于移动端,但通过网页端也能轻松浏览海量视频。平台提供了…

    2026年9月21日
    000
  • windows10如何使用资源监视器查看网络和磁盘活动_windows10资源监视器使用方法

    资源监视器可精确定位Windows 10系统中导致网络延迟或磁盘响应缓慢的高占用进程,通过“网络”和“磁盘”选项卡实时监控各进程的流量、连接、读写速度及响应时间,帮助识别异常程序并分析性能瓶颈。 如果您发现Windows 10系统网络延迟或磁盘响应缓慢,可能是某些进程在后台大量占用资源。资源监视器能…

    2026年9月21日
    100
  • 在Java中如何实现线程优先级控制

    Java中线程优先级通过Thread类实现,取值范围1-10,分别对应MIN_PRIORITY、NORM_PRIORITY和MAX_PRIORITY;新线程继承父线程优先级,可通过setPriority()设置;尽管高优先级线程更可能被调度,但执行顺序不保证,因受操作系统影响;应避免依赖优先级控制关…

    2026年9月21日
    000
  • 如何在Java中使用接口实现多继承效果

    Java不支持多继承,但可通过实现多个接口模拟该效果。类可同时实现Flyable、Swimmable等接口,具备多种行为能力,并能利用默认方法复用逻辑,如Loggable提供日志功能。当多个接口含同名默认方法时,需在类中显式重写以解决冲突。接口用于定义“能做什么”,抽象类描述“是什么”,因类只能单继…

    2026年9月21日
    100
  • 万人同时在线抽奖活动架构

    万人同时在线抽奖活动的系统架构应采用微服务架构、分布式数据库、redis缓存、区块链存储结果,并使用负载均衡和异步处理技术。具体包括:1.采用微服务架构和分布式数据库(如tidb)保证系统稳定性和可扩展性;2.使用redis处理抽奖逻辑,确保高效和随机性;3.将结果存入区块链,保证透明度和可验证性;…

    2026年9月21日
    000
  • 小可AI小程序入口链接_小可AI小程序官方地址

    小可AI小程序官方入口为https://xcx.xiaokeai.com.cn,用户可在社交平台搜索使用;平台支持多轮对话、文本生成、图像理解及语音转文字功能,界面简洁、响应迅速,具备历史记录查看与持续优化的智能算法。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepS…

    2026年9月21日
    000
  • Linux文件和目录管理常见命令

    Linux文件和目录管理依赖于ls、cd、mkdir、rm、cp、mv等核心命令,用于浏览、创建、删除、复制和移动文件与目录;通过find、du、grep等命令可查找文件、定位大文件并清理磁盘空间;使用rename、mmv或脚本可实现批量重命名;为安全起见,应谨慎使用rm命令,推荐结合-i选项或使用…

    2026年9月21日
    000
  • 抖店无货源店铺怎么做?无货源运营核心技巧

    如何打造抖店无货源模式:高效运营实战指南 在当前电商快速发展的趋势下,抖店无货源模式正成为众多创业者的首选。这种模式无需自备库存,极大降低了启动成本和经营风险,但在选品、供应链协同和客户服务方面也提出了更高的要求。本文结合有赞平台的实用功能,深入拆解抖店无货源的搭建流程与关键运营策略,助力商家实现低…

    2026年9月21日
    000
  • 大数据量下的批量导入/导出优化

    在大数据环境下优化批量导入/导出的方法包括:1. 使用批处理技术分批导入/导出数据,减少系统资源压力;2. 采用数据流技术如apache kafka进行实时处理,降低内存占用;3. 利用并行处理技术分配任务到多个处理器或节点,提高处理速度;4. 通过性能监控和调优识别并解决瓶颈点,以提升整体效率。 …

    2026年9月21日
    200
  • 《忍者龙剑传4》明日发售 制作人谈亮点:经典与创新并存!

    白金工作室今日迎来《忍者龙剑传4》(ninja gaiden 4)制作人兼导演中尾裕治的特别公告,正式确认游戏将于10月21日(周二)全球上线。中尾在声明中详细介绍了本作的核心特色,强调在传承系列精髓的同时注入全新机制,为玩家打造既怀旧又充满惊喜的忍者冒险。 特色一:传承与进化的战斗系统 系列经典操…

    2026年9月21日
    000

发表回复

登录后才能评论
关注微信