【问题标题】:How to sort the map as per the word occurrence in a string array如何根据字符串数组中出现的单词对地图进行排序
【发布时间】:2019-05-19 07:39:09
【问题描述】:

我正在编写一个 java 程序逻辑,用于打印带有出现次数和行号的 wrod。下面是代码

package test;
import java.util.HashMap;
 import java.util.Scanner;
 import java.util.Set;

 public class Countcharacters {

/**
 * @param args
 */
static HashMap<String, Integer> countcharact=new HashMap<>();
static HashMap<String, String> linenumbertrack=new HashMap<>();
static int count=1;
static void countwords(String line){
    //System.out.println(line);
    String[] input=line.split("\\s");
    int j=0;
    String linenumber="";
    for(int i=0;i<input.length;i++){
        //System.out.println(input[i]);
        if(countcharact.containsKey(input[i])==true){
            j=countcharact.get(input[i]);
            linenumber=linenumbertrack.get(input[i]);
            countcharact.put(input[i],j+1);
            linenumbertrack.put(input[i],linenumber+", "+count);

        }
        else{
            countcharact.put(input[i], 1);
            linenumbertrack.put(input[i],count+"" );
        }

    }
    count++;


}
public static void main(String[] args) {
    // TODO Auto-generated method stub
   String inp="the quick brown fox jumped over the lazy dog's bowl.\nthe dog was angry with the fox for considering him lazy.";
   String[] line=inp.split("\n");
   for(int i=0;i<line.length;i++){
       Countcharacters.countwords(line[i]);
   }
    Set<String> s=countcharact.keySet();
    for(String c:s){
        System.out.println(c+" "+countcharact.get(c)+" "+"["+linenumbertrack.get(c)+"]");
    }

}

}

我得到的输出是

over 1 [1]
quick 1 [1]
lazy. 1 [2]
lazy 1 [1]
considering 1 [2]
jumped 1 [1]
was 1 [2]
for 1 [2]
angry 1 [2]
brown 1 [1]
him 1 [2]
fox 2 [1, 2]
the 4 [1, 1, 2, 2]
with 1 [2]
bowl. 1 [1]
dog's 1 [1]
dog 1 [2]

但我有两个问题。

第一个:如果您看到“the”的出现次数为 4,但行数为 [1,1,2,2] 而应仅为 [1,2]。

2nd:我想对它们进行排序。它应该首先按基数降序排列,然后按字母顺序排列。

像这样:

the 4 [1,2]
fox 2 [1,2]
lazy 2 [1,2]
angry 1 [1]
bowl 1 [1]
.
.

【问题讨论】:

  • 您遇到问题的代码是什么?你的代码有什么问题?您收到错误消息吗?错误信息是什么?你得到的结果不是你期望的结果吗?你期望什么结果,为什么,你得到的结果是什么,两者有什么不同?您正在观察的行为不是期望的行为吗?期望的行为是什么,为什么,观察到的行为是什么,它们有何不同?请提供minimal reproducible example
  • 嗨,我扩展了我的问题

标签: java algorithm design-patterns collections java-8


【解决方案1】:

最好在类中抽象出数据的逻辑单元。在您的问题中,您有两个明确的单位:

  1. 单词出现(单词字符串和行号)。

        class WordOccurrence {
            private final String word;
            private final int lineNumber;
    
            ...
        }
    
  2. 关于单词的统计信息(出现次数、出现的行号集合等)。

        class WordStats {
            private List<Word> occurrences;
    
            public String getWord() { ... }
            public int getCount() { ... }
            public Set<Integer> getLines() { ... }
        }
    

通过这些课程,您可以首先将您的text 分解为MapListWordOccurrence;因此对于每个不同的单词,Map 将包含一个条目:

  1. key 等于实际的String
  2. 值等于 List 包含 WordOccurrence 对象,因为它在 text 中的每个出现

您可以通过以下方式实现:

    public static Map<String, List<WordOccurrence>> createOccurrencesMap(String text) {
        text = text.replaceAll("\\.", " ");
//      text = text.replaceAll("'s", ""); // dog's != dog ???
        Map<String, List<WordOccurrence>> result = new HashMap<>();
        String[] lines = text.split("\n");
        for (int i = 0; i < lines.length; i++)
            for (String word : lines[i].split("\\s+")) 
                result.computeIfAbsent(word, w -> new ArrayList<>())
                            .add(new WordOccurrence(word, i + 1));

        return result;
    }

然后您可以轻松地将这张地图转换为WordStatsList(使用灵活的参数化标准排序),如下所示:

    List<WordStats> createStats(String text, Comparator<WordStats> sortingCriteria) {
        return createOccurrencesMap(text).values().stream()
                .map(WordStats::new)
                .sorted(sortingCriteria)
                .collect(Collectors.toList());
    }

就是这样!一旦你将问题分解成更小的直观逻辑分组的组件(类、方法、数据结构等),剩下的就是将它们全部连接起来。

以下代码是此解决方案的完整工作演示,供您使用:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class CountWords {

    public static void main(String[] args) {
        String text = "the quick brown fox jumped over the lazy dog's bowl.\nthe dog was angry with the fox for considering him lazy.";
        Comparator<WordStats> sortingCriteria = Comparator
                .comparing(WordStats::getCount).reversed()
                .thenComparing(WordStats::getWord);

        createStats(text, sortingCriteria).forEach(System.out::println);
    }

    public static List<WordStats> createStats(String text, Comparator<WordStats> sortingCriteria) {
        return createOccurrencesMap(text).values().stream()
                .map(WordStats::new)
                .sorted(sortingCriteria)
                .collect(Collectors.toList());
    }

    public static Map<String, List<WordOccurrence>> createOccurrencesMap(String text) {
        text = text.replaceAll("\\.", " ");
//      text = text.replaceAll("'s", ""); // dog's != dog ???
        Map<String, List<WordOccurrence>> result = new HashMap<>();
        String[] lines = text.split("\n");
        for (int i = 0; i < lines.length; i++)
            for (String word : lines[i].split("\\s+")) 
                result.computeIfAbsent(word, w -> new ArrayList<>())
                            .add(new WordOccurrence(word, i + 1));

        return result;
    }

    static class WordStats {
        private List<WordOccurrence> occurrences;

        public WordStats(List<WordOccurrence> words) {
            this.occurrences = words;
        }

        public String getWord() {
            return occurrences.get(0).getWord();
        }

        public int getCount() {
            return occurrences.size();
        }

        public Set<Integer> getLines() {
            return occurrences.stream().map(WordOccurrence::getLineNumber).collect(Collectors.toSet());
        }

        public String toString() {
            return String.format("%s %d %s", getWord(), getCount(), getLines());
        }
    }

    static class WordOccurrence {
        private final String word;
        private final int lineNumber;

        public WordOccurrence(String word, int lineNumber) {
            this.word = word;
            this.lineNumber = lineNumber;
        }

        public String getWord() {
            return word;
        }

        public int getLineNumber() {
            return lineNumber;
        }

        public String toString() {
            return word + "@" + lineNumber;
        }
    }
}

Complete code on GitHub

希望这会有所帮助。

【讨论】:

  • 完美!。感谢 Marco 的详细解释。这将极大地帮助我改进解决此类问题的方法。
猜你喜欢
  • 1970-01-01
  • 2018-06-08
  • 2012-11-04
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
  • 2017-09-11
  • 1970-01-01
  • 2023-04-05
相关资源
最近更新 更多