函数式编程实践记(1)——统计单词频率
2017-04-10 23:39
288 查看
“舅,这次要给我讲解啥子函数式?” YY 问道
“简单点,知道你java基础不错,那就来个 java实现统计单词频率问题” 我答道
结果为:
am 1
come 1
from 1
i 2
is 1
my 1
name 1
old 1
years 1
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
“舅, 你不是说你会Kotlin嘛, 秀一下呗?” YY 挑衅的说。
“哟,可以啊,激将! 没事,那就秀一段给你瞧下, 看好了” 说完,只听见键盘敲击声。不一会,代码展示如下:
结果如下: 最酷炫的是,在一个长长的链式中实现了我们所要的功能。统计词频,按照词频高低排序,词频相同的按照字母字典排序。
my: 2
10: 1
come: 1
from: 1
hes: 1
i: 1
im: 1
is: 1
name: 1
old: 1
years: 1
YY 脑袋凑到我跟前,盯着屏幕,不由的发出 “喔 **, Kotlin这么简洁,而且还是实现了 按照词频 & 字母顺序排序, 牛 x”
“那是,也不看下是谁写的, 你看到思路了没?” 转头我问YY
“大概看懂了”YY回复说
“说说看” 我再次给YY挖坑
“喏,不都是写了注释么? ” YY 指着注释跟我说
“晕~~, 思路是清晰的,也就是其中的排序稍微麻烦些,其他没有难点”我鄙视的说
“YY,那你说说,Java的思路?” 我挑衅的问到
“没问题,只不过我的慢慢来实现” YY 回复到
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
1. 函数传入(String), 将单词放到
2. 遍历所有找到单词, 将首次遇到单词 加入Map, 将重复遇到单词的出现次数加 1
3. 遍历打印 key, value
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
给定一段英文,首先需要识别其中的每个单词,再统计每个单词出现的频率,再对单词进行字母顺序排列,并打印其中出现的频率。
1. 函数传入(String), 将单词放到
2. 遍历所有找到单词, 将首次遇到单词 加入Map, 将重复遇到单词的出现次数加 1
3. 遍历打印 key, value
“TreeMap 有自动排序功能, Matcher实现分词。 该方法将输入的String 中单词统计并放入到TreeMap中,其中的Key,是单词本身,value,单词的次数 ” YY 解释道
打印方式如下:
舅点评:
“YY, Java传统实现中,你这个算是比较优雅的实现了,是Java高级使用。但是,这是命令方式的实现“
”怎么说?“ YY 疑惑的问
”没有发现? 我们需要深入到细节里面, 每个小细节都需要自己实现。第一步做什么,第二部做什么,为了效率,最好都在一个循环内实现。而且,你还偷懒了 把正则表达式匹配单词 写成【”\w+”】, 这个算是细节了,就不追究了“ 我故作恐吓的数落YY
”我都说了,我是个半吊子,没法跟大神比“ YY 辩解道
”莫嘴贫,你试着用java 8 实现下?“ 我回复道
”OK, 我就知道你会说java 8,我会!“ YY 故作镇定的答复
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
“霍, 这么厉害,还找到这篇参考文章,可以嘛” 我鼓励着YY
YY 给出了他自己的java 8 思路。
String wordsTemp = “My name is …, I come from …, I’m 10 … years old! my”;
函数式,有个特点,高度抽象,怎么理解? 不要深入实现的细节,这里的细节可以让Java 8 Stream帮你实现。
对于这个题目,思路可以抽象为:
1. 分词 -> 将一句话中的每个单词分开, 单词之间是以: ” “分开
2. 过滤 -> 过滤不是单词的符号
3. 排序 -> 按照字母字典排序
4. 单词分组统计
不一会儿,YY给出了他的java 8 版本一
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
我指出了 YY 遇到的问题
注意 这个版本是有问题的, 不信看结果。结果少了 I’m, old! 为什么?
name: 1
i: 1
is: 1
from: 1
come: 1
my: 2
years: 1
10: 1
这是因为少考虑了替换,需要把某些字符 ’ !消灭掉,所以,在分词之前加入替换的正则表达式。
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
结果:
im: 1
old: 1
name: 1
i: 1
is: 1
from: 1
come: 1
my: 2
years: 1
10: 1
我还是看到YY的问题: 最后的 (key, value) (单词 单词频率) 没有排序,其实在
“YY, 你完成的不错,虽然不能像Kotlin那样一个链式就搞定了,那是java 8 的问题,而不是你的问题,你已经上道了,后续多练习总结,超越我指日可待” 我故意夸夸YY
“不用给安慰,还是有差距的啊!”YY 认真的说
“看你颓废样,大神又不是说出来的,是真刀真枪干出来的” 我鼓励的说到
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
“简单点,知道你java基础不错,那就来个 java实现统计单词频率问题” 我答道
题目
给定一段英文,找出每个单词使用的频率, 按照String字典顺序排序,并打印出所有单词及其频率的排序列表。如: “My name is …, I come from …, I am … years old!”结果为:
am 1
come 1
from 1
i 2
is 1
my 1
name 1
old 1
years 1
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
“舅, 你不是说你会Kotlin嘛, 秀一下呗?” YY 挑衅的说。
“哟,可以啊,激将! 没事,那就秀一段给你瞧下, 看好了” 说完,只听见键盘敲击声。不一会,代码展示如下:
Kotlin实现
fun main(args: Array<String>) { val wordString = "My name is ..., I come from ..., I_m... he's ... 10 years old! my" wordString .toLowerCase() //*转小写 .replace(Regex("[^a-z0-9A-Z\\s]"), "") //*替换不是字母数字空格的字符为 "" .split(" ") //*空格分词 .filter { it.matches(Regex("\\w+")) } //*过滤单词 .sortedBy { it } //排序 .groupBy { it } //分组 .toList() // 转换为列表 .sortedByDescending { it.second.size } // 按照词频高低排序 .forEach { (key, value) -> println("$key: ${value.size}") } //打印 }
结果如下: 最酷炫的是,在一个长长的链式中实现了我们所要的功能。统计词频,按照词频高低排序,词频相同的按照字母字典排序。
my: 2
10: 1
come: 1
from: 1
hes: 1
i: 1
im: 1
is: 1
name: 1
old: 1
years: 1
YY 脑袋凑到我跟前,盯着屏幕,不由的发出 “喔 **, Kotlin这么简洁,而且还是实现了 按照词频 & 字母顺序排序, 牛 x”
“那是,也不看下是谁写的, 你看到思路了没?” 转头我问YY
“大概看懂了”YY回复说
“说说看” 我再次给YY挖坑
“喏,不都是写了注释么? ” YY 指着注释跟我说
“晕~~, 思路是清晰的,也就是其中的排序稍微麻烦些,其他没有难点”我鄙视的说
“YY,那你说说,Java的思路?” 我挑衅的问到
“没问题,只不过我的慢慢来实现” YY 回复到
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
思路
给定一段英文,首先需要识别其中的每个单词,再统计每个单词出现的频率,再对单词进行字母顺序排列,并打印其中出现的频率。这里给出一个可行的思路:1. 函数传入(String), 将单词放到
Map<String, Integer>中, 使用正则表达式识别单词
2. 遍历所有找到单词, 将首次遇到单词 加入Map, 将重复遇到单词的出现次数加 1
3. 遍历打印 key, value
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
Java版本
YY说出了他的思路:给定一段英文,首先需要识别其中的每个单词,再统计每个单词出现的频率,再对单词进行字母顺序排列,并打印其中出现的频率。
1. 函数传入(String), 将单词放到
Map<String, Integer>中, 使用正则表达式识别单词
2. 遍历所有找到单词, 将首次遇到单词 加入Map, 将重复遇到单词的出现次数加 1
3. 遍历打印 key, value
private static Map<String, Integer> wordFreq(String wordsString) { TreeMap<String, Integer> wordMap = new TreeMap<>(); Matcher matcher = Pattern.compile("\\w+").matcher(wordsString); while (matcher.find()) { String word = matcher.group().toLowerCase(); if (wordMap.get(word) == null) { wordMap.put(word, 1); }else { wordMap.put(word, wordMap.get(word) + 1); } } return wordMap; }
“TreeMap 有自动排序功能, Matcher实现分词。 该方法将输入的String 中单词统计并放入到TreeMap中,其中的Key,是单词本身,value,单词的次数 ” YY 解释道
打印方式如下:
String wordsTemp = "My name is ..., I come from ..., I am ... years old!"; for (Entry<String, Integer> entry : wordFreq(wordsTemp).entrySet()) { out.println(entry.getKey() + " " + entry.getValue()); }
舅点评:
“YY, Java传统实现中,你这个算是比较优雅的实现了,是Java高级使用。但是,这是命令方式的实现“
”怎么说?“ YY 疑惑的问
”没有发现? 我们需要深入到细节里面, 每个小细节都需要自己实现。第一步做什么,第二部做什么,为了效率,最好都在一个循环内实现。而且,你还偷懒了 把正则表达式匹配单词 写成【”\w+”】, 这个算是细节了,就不追究了“ 我故作恐吓的数落YY
”我都说了,我是个半吊子,没法跟大神比“ YY 辩解道
”莫嘴贫,你试着用java 8 实现下?“ 我回复道
”OK, 我就知道你会说java 8,我会!“ YY 故作镇定的答复
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
Java 8实现
”我是参考: Java 8 中的 Streams API 详解 这篇文章熟悉 Java 8 Stream 常用API的 ” YY 首先解释下“霍, 这么厉害,还找到这篇参考文章,可以嘛” 我鼓励着YY
YY 给出了他自己的java 8 思路。
函数式思路
YY没有刻意去记Stream 的各种API,只是慢慢的接触这些API,再慢慢使用就可以了。我更在乎YY的思路。针对题目来说,YY跳出之前的思维框框。以下列文字为例, 找出其中的单词,并统计出现的频率?String wordsTemp = “My name is …, I come from …, I’m 10 … years old! my”;
函数式,有个特点,高度抽象,怎么理解? 不要深入实现的细节,这里的细节可以让Java 8 Stream帮你实现。
对于这个题目,思路可以抽象为:
1. 分词 -> 将一句话中的每个单词分开, 单词之间是以: ” “分开
2. 过滤 -> 过滤不是单词的符号
3. 排序 -> 按照字母字典排序
4. 单词分组统计
不一会儿,YY给出了他的java 8 版本一
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
java 8 版本一
private static void textCount(@NotNull String text) { Arrays.stream(text.toLowerCase() //小写 .split(" ")) //分词 .filter(word -> word.matches("\\w+")) //过滤 .sorted(Comparator.naturalOrder()) //字典排序 // .forEach(s -> out.println(s)); //调试打印 .collect(groupingBy(word -> word)) //分组归类 .forEach((key, value) -> out.println(key + ": " + value.size())); //打印 key, value }
我指出了 YY 遇到的问题
注意 这个版本是有问题的, 不信看结果。结果少了 I’m, old! 为什么?
name: 1
i: 1
is: 1
from: 1
come: 1
my: 2
years: 1
10: 1
这是因为少考虑了替换,需要把某些字符 ’ !消灭掉,所以,在分词之前加入替换的正则表达式。
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
版本二
private static void textCount(@NotNull String text) { Arrays.stream(text.toLowerCase() .replaceAll("[^a-z0-9A-Z\\s]", "") //*新增替换特殊字符* .split(" ")) .filter(word -> word.matches("\\w+")) .sorted(Comparator.naturalOrder()) // .forEach(s -> out.println(s)); .collect(groupingBy(word -> word)) .forEach((key, value) -> out.println(key + ": " + value.size())); }
结果:
im: 1
old: 1
name: 1
i: 1
is: 1
from: 1
come: 1
my: 2
years: 1
10: 1
我还是看到YY的问题: 最后的 (key, value) (单词 单词频率) 没有排序,其实在
.sorted(Comparator.naturalOrder())后,排序好了,但是
.collect(groupingBy(word -> word))破坏了, groupingBy并不是字典顺序来分组,他是乱序的。而且还因为
collect返回值不是Stream, 导致无法再次使用 【.】 去做进一步的函数调用,所以 这里没有办法使用一个函数调用链 来实现。只能把
Arrays.stream的返回值保存到 一个Map中,然后再使用Map迭代方式去排序再打印。参考实现:
private static void textCount(@NotNull String text) { Map<String, List<String>> map = Arrays.stream(text.toLowerCase() .replaceAll("[^a-z0-9A-Z\\s]", "") .split(" ")) .filter(word -> word.matches("\\w+")) .sorted(Comparator.naturalOrder()) .collect(groupingBy(word -> word)); TreeMap<String, Integer> treeMap = new TreeMap<>(); for(Entry<String, List<String>> entry : map.entrySet()) { treeMap.put(entry.getKey(), entry.getValue().size()); } treeMap.forEach((key, value) -> out.println(key + " " + value)); }
“YY, 你完成的不错,虽然不能像Kotlin那样一个链式就搞定了,那是java 8 的问题,而不是你的问题,你已经上道了,后续多练习总结,超越我指日可待” 我故意夸夸YY
“不用给安慰,还是有差距的啊!”YY 认真的说
“看你颓废样,大神又不是说出来的,是真刀真枪干出来的” 我鼓励的说到
【木丁糖 http://blog.csdn.net/shrimpcolo 未经允许严禁转载,请尊重作者劳动成果。[Q群联系我:631353571】
相关文章推荐
- 【学习笔记】C#中HashTable和快速排序的用法,从单词频率统计小程序写起
- 利用visual VM 分析统计单词频率程序
- python统计单词频率基本算法。
- 使用Java统计英文文章的单词频率。
- python统计文本字符串里单词出现频率的方法
- 基于bf算法统计文本中某个单词出现的频率
- 统计文本中各单词出现的频率(JavaWeb)
- 统计一篇英文文章内每个单词出现频率,并返回出现频率最高的前10个单词及其出现次数
- 统计一段文字中出现频率最高的10个单词(c语言)
- python学习之文章中单词出现频率统计
- 统计文本文件中单词出现频率(用java集合框架编写)
- Hadoop:使用原生python编写MapReduce来统计文本文件中所有单词出现的频率功能
- 利用java集合框架统计单词的频率
- 个人项目:统计文本中的单词出现频率
- python实现统计文本中单词出现的频率
- 实现一个控制台程序,给定一段英文字符串,统计其中各个英文单词(4字符以上含4字符)的出现频率。
- 统计文件中各单词出现的频率(二叉排序树实现)
- linux bash shell 统计一个文本中 单词 频率的 脚本详解
- 【学习笔记】C#中HashTable和快速排序的用法,从单词频率统计小程序写起
- 【转】统计一篇文章中单词出现的频率(java 版)