7-2 jmu-Java&Python-统计文字中的单词数量并按出现次数排序分数(答案附注释)java

原题

7-2 jmu-Java&Python-统计文字中的单词数量并按出现次数排序

分数 25

作者 郑如滨

单位 集美大学

现在需要统计若干段文字(英文)中的单词数量,并且还需统计每个单词出现的次数

注1:单词之间以空格(1个或多个空格)为间隔。
注2:忽略空行或者空格行。

基本版:
统计时,区分字母大小写,且不删除指定标点符号。

进阶版:

  1. 统计前,需要从文字中删除指定标点符号!.,:*?。 注意:所谓的删除,就是用1个空格替换掉相应字符。
  2. 统计单词时需要忽略单词的大小写。

ps:

输入说明

若干行英文,最后以!!!!!为结束。

输出说明

单词数量
出现次数排名前10的单词(次数按照降序排序,如果次数相同,则按照键值的字母升序排序)及出现次数。

输入样例1

failure is probably the fortification in your pole

it is like a peek your wallet as the thief when you
are thinking how to spend several hard-won lepta
          
when you are wondering whether new money it has laid
background because of you then at the heart of the
     
most lax alert and most low awareness and left it

godsend failed
!!!!!

输出样例1

46
the=4
it=3
you=3
and=2
are=2
is=2
most=2
of=2
when=2
your=2

输入样例2

Failure is probably The fortification in your pole!

It is like a peek your wallet as the thief when You
are thinking how to. spend several hard-won lepta.

when yoU are? wondering whether new money it has laid
background Because of: yOu?, then at the heart of the
Tom say: Who is the best? No one dare to say yes.
most lax alert and! most low awareness and* left it

godsend failed
!!!!!

输出样例2

54
the=5
is=3
it=3
you=3
and=2
are=2
most=2
of=2
say=2
to=2

答案

import java.util.*;
public class Main {
public static void main(String[] args) {
	Scanner sc = new Scanner(System.in);
    StringBuilder builder = new StringBuilder();
    String line = sc.nextLine();
    while (!line.equals("!!!!!")) {
        builder.append(line).append("\n");
        line = sc.nextLine();
    }
    String text = builder.toString();
    
    // 创建一个HashMap来存储单词和出现次数
    Map<String, Integer> wordcountMap = new HashMap<String, Integer>();
    
    // 将文本中的标点符号替换为空格
    text = text.replaceAll("[!.,:*?]", " ");
    
    // 将文本按空格分割成单词数组
    String[] wordStrings = text.split("\\s+");
    
    // 遍历单词数组,统计每个单词的出现次数
    for (String word : wordStrings) {
		wordcountMap.put(word.toLowerCase(),wordcountMap.getOrDefault(word.toLowerCase(), 0)+1);
	}
    
    // 将HashMap的键值对转化为List,以便进行排序
    List<Map.Entry<String, Integer>> entries = new ArrayList<Map.Entry<String,Integer>>(wordcountMap.entrySet());
    
    // 根据单词出现次数进行排序,如果出现次数相同,则按字母顺序排序
    Collections.sort(entries, (a, b) -> {
        if (a.getValue().equals(b.getValue())) {
			return a.getKey().compareTo(b.getKey());
		}
        else {
			return b.getValue().compareTo(a.getValue());
		}
    });
    
    // 输出不重复单词的数量
    System.out.println(wordcountMap.size());
    
    // 输出出现次数最多的前10个单词及其出现次数
    for (int i = 0; i < Math.min(10, entries.size()); i++) {
        Map.Entry<String, Integer> entry = entries.get(i);
        System.out.println(entry.getKey() + "=" + entry.getValue());
    }
}
}

 为什么用StringBuilder?

StringBuilderStringBuffer都是用于处理可变字符串的类,它们的主要区别在于线程安全性和性能。(题目需要对字符串进行更改等操作故使用这两类可变字符串类)

  1. 线程安全性:

    • StringBuffer是线程安全的,它的方法都是同步的,可以在多线程环境下使用,但是同步操作会带来一定的性能开销。
    • StringBuilder是非线程安全的,它的方法不是同步的,因此在单线程环境下使用效率更高。但是在多线程环境下使用StringBuilder需要自行处理同步问题。
  2. 性能:

    • StringBuffer的同步操作使得它的性能相对较低,适用于多线程环境或需要线程安全的场景。
    • StringBuilder不需要同步操作,因此性能相对较高,适用于单线程环境或无需线程安全的场景。

在大多数情况下,如果在单线程环境下使用可变字符串,推荐使用StringBuilder,因为它的性能更好。只有在多线程环境或需要线程安全的情况下,才需要使用StringBuffer

wordcountMap.size()计算的是什么大小?

wordcountMap.size()方法用于返回wordcountMap中键值对的数量,即wordcountMap的大小或元素个数。

wordcountMap中,每个键都是唯一的,因此size()方法返回的是wordcountMap中不同键的数量。对于键值对(key, value)wordcountMap中的大小就是键的数量。

例如,如果有一个Map<String, Integer>,其中包含以下键值对:

{"apple": 3, "banana": 2, "orange": 5}

那么map.size()将返回3,因为Map中有三个不同的键。

需要注意的是,size()方法的时间复杂度为O(1),即它的执行时间与Map的大小无关,因为Map会在内部维护一个计数器来跟踪键值对的数量。

ps:数了数题目中的个数,对比输出样例发现是输出出现了多少个不同的单词,而不是所有单词的总数,故可以使用该方法返回键值对数量。

 (a, b) ->{...}是什么?Lambda表达式?

Collections.sort(entries, (a, b) -> {
    if (a.getValue().equals(b.getValue())) {
        return a.getKey().compareTo(b.getKey());
}
    else {
        return b.getValue().compareTo(a.getValue());
}
    });

使用了Lambda表达式,其中(a, b)表示两个要比较的对象,->表示Lambda表达式的箭头,后面的代码块定义了比较的逻辑。

Lambda表达式是Java 8引入的一种新的语法特性,用于简化函数式接口的实现。它可以看作是一种匿名函数,可以作为参数传递给方法或存储在变量中。

Lambda表达式的语法如下:

(parameters) -> expression
或
(parameters) -> { statements; }

其中,parameters是参数列表,可以为空或包含一个或多个参数。expression是单个表达式,或者是一个代码块(用{}括起来的一组语句)。如果使用代码块,必须使用return语句返回一个值。

Lambda表达式可以用于实现函数式接口,即只有一个抽象方法的接口。在使用Lambda表达式时,可以省略接口的实现类,直接在方法参数中传递Lambda表达式。

Lambda表达式的优点是简化了代码的编写,尤其是对于函数式编程和处理集合、并行处理等场景非常方便。它提供了一种更简洁、更灵活的方式来编写代码。

Lambda表达式的类怎么判断?

根据上下文和目标类型来推断的。在使用Lambda表达式时,编译器会根据Lambda表达式的上下文和目标类型来确定Lambda表达式的类型。

使用比较器Comparator实现排序

  1. 创建一个实现Comparator接口的类,比如命名为WordComparator。
class WordComparator implements Comparator<Map.Entry<String, Integer>> {
    @Override
    public int compare(Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) {
        if (a.getValue().equals(b.getValue())) {
            return a.getKey().compareTo(b.getKey());
        } else {
            return b.getValue().compareTo(a.getValue());
        }
    }
}
  1. 在排序的地方,将Lambda表达式替换为WordComparator类的实例。
Collections.sort(entries, new WordComparator());

text = text.replaceAll("[!.,:*?]", " "); 这啥啊?

1.正则表达式

使用正则表达式将文本中的标点符号替换为空格。正则表达式[!.,:*?] 表示匹配任意一个字符是 !.,:* 或 ? 中的一个,然后将匹配到的字符替换为一个空格。

例如,如果文本中有句子:"Hello, world! How are you?",经过text.replaceAll("[!.,:*?]", " ")操作后,文本变为:"Hello world How are you ",其中标点符号被替换为空格。

ps:什么是正则表达式??简单说是一种文本匹配与处理工具,较复杂,自行百度

2.replaceAll()

replaceAll 是Java中String类的方法,用于将字符串中的某个字符或字符序列替换为新的字符或字符序列。

它的用法如下:

String result = str.replaceAll(regex, replacement);

其中,str 是要进行替换操作的字符串,regex 是要被替换的字符或字符序列的正则表达式,replacement 是用于替换的新字符或字符序列。

replaceAll 方法会返回一个新的字符串,该字符串是在原字符串的基础上进行替换后得到的结果。

例如,假设有一个字符串 str = "Hello, world!",我们想将其中的逗号替换为空格,可以使用以下代码:

String result = str.replaceAll(",", " ");
System.out.println(result); // 输出: "Hello  world!"

在这个例子中,"," 是要被替换的字符序列的正则表达式," " 是用于替换的新字符序列。replaceAll 方法会将字符串中的逗号替换为空格,得到新的字符串 "Hello world!"

3.replace 和 replaceAll区别

首先答案代码中replaAll部分可以替换为以下代码

String result = text.replace("!", " ")
                   .replace(".", " ")
                   .replace(",", " ")
                   .replace(":", " ")
                   .replace("*", " ")
                   .replace("?", " ");

或是

String result = text.replaceAll("!", " ")
                   .replaceAll("\\.", " ")
                   .replaceAll(",", " ")
                   .replaceAll(":", " ")
                   .replaceAll("\\*", " ")
                   .replaceAll("\\?", " ");

 发现不同了吗?

在使用replaceAll时,由于第一个参数可以为正则表达式,而部分符号在其中又为特殊字符,故需要进行转义,例如.和*,其中正则表达式中的空格用\\s表示。

replace 和 replaceAll 是字符串类(java.lang.String)中的两个方法,用于替换指定的字符或字符序列。它们之间的主要区别在于:

  1. 参数类型:replace 方法接受两个参数,都是字符或字符序列;而 replaceAll 方法接受两个参数,第一个参数是正则表达式(字符串),第二个参数是替换字符串。

  2. 替换方式:replace 方法执行简单的文本替换,只能替换固定的字符或字符序列;而 replaceAll 方法执行基于正则表达式的替换,可以实现更复杂的模式匹配和替换。

  3. 正则表达式:replaceAll 方法的第一个参数是一个正则表达式,用于指定要匹配的模式。正则表达式可以包含特殊字符和元字符,用于匹配更灵活的模式。

  4. 转义字符:由于 replaceAll 方法的第一个参数是正则表达式,而正则表达式中有一些特殊字符需要进行转义,因此在使用 replaceAll 方法时需要注意对特殊字符进行转义,例如使用 \\. 表示字面意义上的点。

总的来说,replace 方法适用于简单的固定替换,而 replaceAll 方法适用于复杂的模式匹配和替换。根据具体的需求,选择合适的方法来进行替换操作。

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用 Python 的字典(dict)来实现单词数量统计排序。 首先,我们需要读入文本文件,并将其转换为一个字符串。可以使用 Python 的 open 函数打开文件,并使用 read 方法读取文件内容。为了方便处理,我们可以将所有字母都转换为小写字母。 ```python with open('text.txt', 'r') as f: text = f.read().lower() ``` 接下来,我们需要将字符串拆分成单个单词,并统计它们的出现次数。可以使用 Python 的 split 方法来拆分字符串,并使用一个字典来存储每个单词出现次数。如果字典已经存在该单词,则将其出现次数加一;否则,在字典添加该单词并将其出现次数设置为一。 ```python word_count = {} for word in text.split(): if word in word_count: word_count[word] += 1 else: word_count[word] = 1 ``` 最后,我们可以根据单词出现次数对字典进行排序,并将结果打印来。可以使用 Python 的 sorted 函数和 lambda 表达式来实现排序。 ```python sorted_word_count = sorted(word_count.items(), key=lambda x: x[1], reverse=True) for word, count in sorted_word_count: print(f'{word}: {count}') ``` 完整代码如下: ```python with open('text.txt', 'r') as f: text = f.read().lower() word_count = {} for word in text.split(): if word in word_count: word_count[word] += 1 else: word_count[word] = 1 sorted_word_count = sorted(word_count.items(), key=lambda x: x[1], reverse=True) for word, count in sorted_word_count: print(f'{word}: {count}') ``` 其,text.txt 是要统计的文本文件的文件名。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值