Java如何用HaspMap统计次数并排序详解

news/2024/12/19 11:27:36/文章来源:https://www.cnblogs.com/ivanlee717/p/18616804

java统计单词频率

继上一讲Java用PDFTextStripper来解析pdf文件提取文字 - ivanlee717 - 博客园讲了如何接收和解析pdf之后,我们把pdf文件全部转为了String类型的字符串,那么这一讲聊聊怎么去统计每个词出现的频率。

正则过滤

首先我们需要把单词弄出来,把其他的文字过滤掉。

Pattern pattern = Pattern.compile("\\b[a-z]+\\b");
Matcher matcher = pattern.matcher(s.toLowerCase());

\\b 是一个元字符(metacharacter),表示单词边界。它匹配的是位置,而不是具体的字符。它确保匹配的单词前后是单词边界,即单词的开头或结尾,或者与非单词字符相邻。例如,在字符串 "hello regina" 中,\b 会匹配 h 之前、o 之后、r 之前和 a 之后的位置。

具体来说,\\b 匹配以下几种情况:

  • 字符串的开头或结尾。
  • 一个单词字符(字母、数字、下划线)紧接在非单词字符(如空格、标点符号等)之后,或反之亦然。

[a-z] 是一个字符类,表示匹配任意一个小写字母(从 a 到 z)。

  • [A-Za-z]:匹配任意大小写字母。
  • [0-9]:匹配任意数字。
  • [a-zA-Z0-9_]:匹配任意字母、数字或下划线(相当于 \w)。
  • [aeiou]:匹配任意元音字母。

+是一个量词,表示前面的元素必须出现一次或多次。

量词可以应用于单个字符、字符类或更复杂的表达式。常见的量词包括:

  • *:匹配零次或多次。

  • +:匹配一次或多次。

  • ?:匹配零次或一次。

  • {n}:精确匹配 n 次。

  • {n,}:匹配至少 n 次。

  • {n,m}:匹配至少 n 次,最多 m 次。

第二个\\b仍然表示单词边界,但它出现在模式的末尾,确保匹配的单词以单词边界结束。

在设置好匹配规则以后,就要去进行匹配了。matcher(CharSequence input):这是 Pattern 类的一个实例方法,用于创建一个 Matcher 对象。Matcher 对象可以在给定的输入字符串(input)中查找与正则表达式模式匹配的子串。image-20241219101602770

find():尝试找到下一个与模式匹配的子串。如果找到匹配项,则返回 true,并将匹配位置更新到下一个匹配项的起始位置
group():返回当前匹配的子串。只有在调用 find() 或 matches() 成功后,才能调用 group()。
start() 和 end():分别返回当前匹配项的起始和结束索引。
replaceAll(String replacement)replaceFirst(String replacement):用于替换所有或第一个匹配项。
reset():重置 Matcher,使其从头开始匹配新的输入字符串。

然后我们用一个哈希表来存储每个单词的出现频率。

HashMap<String, Integer> wordCount = new HashMap<>();
while (matcher.find()) {String word = matcher.group();if (word.length() > 5) {wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);}
}

我们一次来解析查到的每一个步骤。首先如果一直有单词出现,那么match.find()就会一直为true,然后始终在遍历循环。

image-20241219101655851

image-20241219101706036

每一次遍历成功之后都会把单词组在一起返回一个String,循环往复我们就可以把所有单词都遍历一次。

HashMap

getOrDefault(K key, V defaultValue):这是 Map 接口的一个方法,用于获取指定键(key)对应的值。如果该键不存在,则返回提供的默认值(defaultValue)。代码里面我们先查找这个ielts的单词,发现并没有存储,于是设置成0 。

put(K key, V value):这是 Map 接口的一个方法,用于将指定的键值对插入到 Map 中。如果该键已经存在,则更新其对应的值。

image-20241219103133720

运行put方法之后,image-20241219103215488

while循环结束之后,就形成了一个统计表,然后我们对统计表按照次数排个序。

wordCount.entrySet().stream(): entrySet()是 Map 接口的一个方法,返回一个包含所有键值对的 Set<Map.Entry<String, Integer>>。每个 Map.Entry 对象代表一个键值对。stream()是 Collection 接口的一个方法,用于将集合转换为一个流(Stream)。流是数据的序列化容器,支持各种中间操作和终端操作,可以进行链式调用,从而实现高效的批量数据处理。

filter(Predicate<? super T> predicate):这是 Stream 接口的一个中间操作,用于筛选流中的元素。它接受一个 Predicate 函数式接口作为参数,该接口定义了一个布尔表达式,用于决定是否保留某个元素。entry -> entry.getValue() >= 10是一个 lambda 表达式,表示筛选条件。entry 是当前处理的 Map.Entry<String, Integer> 对象,entry.getValue() 返回该单词的出现次数。这个条件确保只有出现次数大于等于 10 的单词会被保留。

entry -> entry.getValue() >= 10 中的 -> 是 Java 8 引入的 lambda 表达式 的一部分。Lambda 表达式提供了一种简洁的方式来表示匿名函数(即没有名字的函数),通常用于实现函数式接口(即只有一个抽象方法的接口)。在你的例子中,-> 分隔了 lambda 表达式的参数列表和主体部分。

Lambda 表达式的基本语法如下:
(parameters) -> expression(parameters) -> { statements; }
(parameters):参数列表,可以包含零个、一个或多个参数。如果只有一个参数且类型可以推断出来,括号可以省略。
->:箭头符号,分隔参数列表和表达式或语句块。
expression:单个表达式,其结果将作为 lambda 表达式的返回值。如果需要多条语句,则需要用大括号 {} 包围,并使用 return 语句显式返回值。

大概知道这种表达方式之后,那我们的排序的语法也就清楚了。

sorted(Comparator<? super T> comparator):这是 Stream 接口的一个中间操作,用于对流中的元素进行排序。它接受一个 Comparator 函数式接口作为参数,该接口定义了元素之间的比较规则。
(e1, e2) -> e2.getValue().compareTo(e1.getValue()):这也是一个 lambda 表达式,表示自定义的比较器。e1 和 e2 是两个 Map.Entry<String, Integer> 对象,e1.getValue() e2.getValue() 分别返回它们的出现次数。compareTo 方法用于比较两个 Integer 值。这里的比较规则是按出现次数从高到低排序,因此我们使用 e2.getValue().compareTo(e1.getValue()),即先比较 e2 的值,再比较 e1 的值。

collect(Collector<? super T, A, R> collector):这是 Stream 接口的一个终端操作,用于将流中的元素收集到一个集合中。它接受一个 Collector 对象作为参数,定义了如何将流中的元素聚集在一起。
Collectors.toList():这是 Collectors 类的一个静态方法,返回一个 Collector,用于将流中的元素收集到一个 List 中。最终的结果是一个 List<Map.Entry<String, Integer>>,其中每个 Map.Entry 对象代表一个单词及其出现次数。

image-20241219104839479

在遍历一遍之后我们可以得到一个这样的键值对现在我们编写排序代码。

List<Map.Entry<String, Integer>> sortedWords = wordCount.entrySet().stream().filter(entry -> entry.getValue() >= 10).sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue())).collect(Collectors.toList());

image-20241219105245765

List<Map.Entry<String, Integer>>这是一个什么类型的数据?

Map.Entry<String, Integer> 与 HashMap 有密切的关系,但它们并不是同一个东西。Map.Entry 是 Map 接口的一部分,而 HashMap 是 Map 接口的一个具体实现类。

  1. Map.Entry<K, V>
    Map.Entry<K, V>:这是 Map 接口中的一个静态内部接口,表示 Map 中的一个键值对(key-value pair)。每个 Map.Entry 对象包含两个部分:
    键 (K):类型为 K 的键。
    值 (V):类型为 V 的值。
    主要方法:
    K getKey():返回该键值对的键。
    V getValue():返回该键值对的值。
    V setValue(V value):设置该键值对的值,并返回旧值。
    用途:Map.Entry 通常用于遍历 Map 中的键值对。例如,entrySet() 方法返回一个包含所有键值对的 Set<Map.Entry<K, V>>,你可以通过迭代这个集合来访问每个键值对。
  2. HashMap<K, V>
    HashMap<K, V>:这是 Map 接口的一个具体实现类,提供了一种基于哈希表的数据结构,用于存储键值对。HashMap 允许你以键为索引快速查找、插入和删除键值对。
    特点:
    非线程安全:HashMap 不是线程安全的,如果多个线程同时访问并修改同一个 HashMap,可能会导致数据不一致的问题。如果你需要在多线程环境中使用类似的结构,可以考虑使用 ConcurrentHashMap Collections.synchronizedMap()
    允许一个 null 键和多个 null 值:HashMap 允许一个键为 null,并且可以有多个值为 null。
    平均时间复杂度:在大多数情况下,HashMap 的查找、插入和删除操作的时间复杂度为 O(1),即常数时间复杂度。
for (Map.Entry<String, Integer> entry : words) {String word = entry.getKey();Function(word);
}

所以如果要遍历一个hashmap类型的东西,一般我们都会把他变成一种List<Map.Entry<String, Integer>>来循环获取,这样也比较方便去调用数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/855313.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IEC101/140 监视点与控制点

IEC101/140 监视点与控制点 IEC-60870-5-104 协议适用于远程控制设备和系统,通过数据传输来监控和控制地理上广泛的过程。该协议结合了 IEC-60870-5-101 协议和 TCP/IP 提供的传输功能。 任何使用 IEC-60870-5-104 协议的应用程序都将有一个主站(控制站)和一个或多个从站(受…

android emulator 设置代理

android emulator 设置代理 由于开发的 app 需要访问 google 服务,那么跑虚拟机的时候就需要设置网络代理,试了几种方法都没成功,记录一下 因为已知我开发电脑的代理地址和端口,只需要把电脑的代理设置到 emulator 上就可以了 设置Android Studio代理 先在Android Studio上…

Redux Thunk深入理解与使用指南

一、什么是 Redux Thunk? 在 React 应用中,Redux 是一个常用的状态管理工具。但 Redux 本身是一个纯同步状态管理工具,它的 dispatch 方法默认只支持同步操作。如果我们想要处理异步逻辑(如请求接口、延时操作等),需要使用中间件(middleware)。Redux Thunk 就是一个用于…

无人车队运营需要的远程驾驶平台

无人车队在全时商业化运营的过程中,不可避免会出现自动驾驶无法处理的极端、异常场景。为提高运营效率,避免配备随车安全员带来的成本上升与风险增加,使用远程驾驶系统对无人车队运营进行辅助是较为经济且可靠的解决方案。经纬恒润远程驾驶系统具备丰富的功能和宽广的能力覆…

求职者必备:如何用管理软件实现高效的Offer规划

一、毕业季Offer规划的复杂性 毕业季的Offer规划不仅仅是简单的找工作过程,更是一次紧张的时间赛跑。从投递简历、面试安排、薪资谈判到最终的决定,整个过程充满了大量的任务和步骤。这些任务和环节涉及不同的公司、职位要求、面试形式以及其他各种变量。如果没有一个高效的工…

函数式接口之方法作为参数

在现实开发中,肯定会遇到这样一种情况,有几个业务场景,里面的大部分业务逻辑都一样,只有某些逻辑不同,而这些不同的逻辑又依赖于前面的逻辑,你会选择写重复代码去实现还是选择抽取公共方法,对那些不同的逻辑做单独处理?是不是理解起来比较抽象,简单就一句话,怎么把方…

胖东来成功背后的管理智慧:零售行业如何借鉴?

零售行业通过选择合适的看板软件、实施看板管理以及持续优化与改进等步骤,可以实现管理优化和效率提升。这将有助于企业更好地应对市场竞争、提高客户满意度和实现可持续发展。胖东来创始人于东来在社交平台分享了胖东来商贸集团2024年的营业情况。数据显示,截至2024年11月26…

旅游公司各部门联动,何种办公软件能高效协同?

在旅游行业蓬勃发展且竞争日益激烈的当下,高效的团队协作与个人学习效率提升成为旅游公司脱颖而出的关键因素。尤其是对于 MBTI 类型中倾向于有序规划的 J 人而言,可视化的团队协作办公软件犹如得力助手,能够让复杂的旅游业务流程清晰呈现,促进信息的高效流通与任务的顺利推…

linux操作系统安装

1.centenos镜像文件下载 2.创建一个虚拟机 1)打开VMware软件,选择创建新的虚拟机,在弹出的虚拟机向导的窗口选择自定义配置,点击下一步;2)默认设置3)选择稍后安装系统4)客户机操作系统选择Linux,版本选择CentOS 7(64位)5)命名虚拟机,选择存储路径6)处理器配置根据…

如何在宝塔面板中检查和开启path_info支持?

在宝塔面板中,检查和开启path_info支持的步骤如下:登录宝塔面板:打开浏览器,输入宝塔面板的地址(例如:http://你的域名:8888),使用管理员账号登录。进入网站管理页面:在宝塔面板首页,找到你需要配置的网站,点击“设置”按钮。进入PHP设置:在网站设置页面中,找到“…

大模型平台汇总说明

国外大模型平台 Openapi Anthropic Meta google国内大模型平台 百度 文心一言厂商 模型地址优势百度 文心一言 https://yiyan.baidu.com/ 支持文生图支持联网支持图生文支持读取文档支持生成图表商业信息查询生成思维导图 本文来自博客园,作者:王竹笙,转载请注明原文链接:…

规划新一年,提升效率:跨年日程管理与计划软件的完美结合

一、跨年日程规划的挑战 跨年作为时间的节点,往往意味着新的开始。许多人在这一时期都会进行新一年的规划,制定目标、任务和行动计划。无论是个人的生活规划,还是团队或公司的年度战略,跨年日程规划面临的挑战主要包括:1.1 任务繁多,易遗漏 跨年日程通常包含从目标设定、…