0

So, I have made a program to count words by occurrence, and print them by des order, also if the words have same frequency, they will be sorted alphabetically (also list contains Russian words, if the words have same frequency, the Russian words will go down from English words, and Russian words will be sorted Alphabetically as well).

  • if the word length is less then 4, or their frequency is less than 10, I want to remove them.

  • I need to check if word contains .,!? to remove them, and add them without those chars. For example: hello! will be added hello, or Bye! will be added Bye

Here is a good example for it:

лицами-18
Apex-15
azet-15
xder-15
анатолю-15
андреевич-15
батальона-15
hello-13
zello-13
полноте-13

Here is my code:

public String countWords(List<String> lines) {

    StringBuilder input = new StringBuilder();
    StringBuilder answer = new StringBuilder();

    for (String line : lines){
        if(line.length() > 3){
            if(line.contains(",")){
                line = line.replace(",", "");
                input.append(line).append(" ");
            }else if (line.contains(".")){
                line = line.replace(".", "");
                input.append(line).append(" ");
            }else if (line.contains("!")){
                line = line.replace("!", "");
                input.append(line).append(" ");
            }else if (line.contains("?")){
                line = line.replace("?", "");
                input.append(line).append(" ");
            }else{
                input.append(line).append(" ");
            }
        }
    }

    String[] strings = input.toString().split("\\s");

    List<String> list = new ArrayList<>(Arrays.asList(strings));

    Map<String, Integer> unsortMap = new HashMap<>();

    while (list.size() != 0){
        String word = list.get(0);
        int freq = Collections.frequency(list, word);
        if (word.length() >= 4 && freq >= 10){
            unsortMap.put(word.toLowerCase(), freq);
        }

        list.removeAll(Collections.singleton(word));
    }

    List<String> sortedEntries = unsortMap.entrySet().stream()
            .sorted(Comparator.comparingLong(Map.Entry<String, Integer>::getValue)
                    .reversed()
                    .thenComparing(Map.Entry::getKey)
            )
            .map(it -> it.getKey() + " - " + it.getValue())
            .collect(Collectors.toList());

    for (int i = 0; i < sortedEntries.size(); i++) {
        if(i<sortedEntries.size()-1) {
            answer.append(sortedEntries.get(i)).append("\n");
        }
        else{
            answer.append(sortedEntries.get(i));
        }
    }

    return answer.toString();

}

So, as you can see my code works fine. However, I want to go beyond this, and I want to write the same logic without using If, While, For. I want to write the same logic with streams or lambdas. As you can see I was able to write one part of the logic, to sort the list. However, I was not able to write the other parts where I have if and while loops. I am new to Streams and I want to know if there is some way I could write the same code, without using for, while, if statements, and only use streams.

Nowhere Man
  • 19,170
  • 9
  • 17
  • 42
  • Look at `Collectors.joining` – tgdavies Aug 07 '21 at 07:43
  • For now your if/else remove only the FIRST special char, not all, that normal ? – azro Aug 07 '21 at 07:50
  • For the first while part you can check [here](https://stackoverflow.com/questions/53054193/counting-number-of-duplicates-using-arraylist-in-java) using `groupingBy` and `counting` with filtering. – Eklavya Aug 07 '21 at 07:54
  • 2
    It seems similar questions have been posted from different accounts here for the last few days: user givexa: 1) [how to sort hashmap of string and integer by value](https://stackoverflow.com/questions/68653561/how-to-sort-hashmap-of-string-and-integer-by-value-and-in-case-of-duplicate-the) 2) [already deleted: how to write code with stream alternative](https://stackoverflow.com/questions/68661534/how-to-write-code-with-stream-alternative), as [Baron: alternative of streams in sorting..](https://stackoverflow.com/questions/68662616/alternative-of-streams-in-sorting-frequently-occurred-words) – Nowhere Man Aug 07 '21 at 08:29

1 Answers1

0

Use

  • filter and flatMap for the first filtering and replacement part
    • use String.replaceAll to remove the 4 chars at once
    • replace with " " and not "" to avoid Hey!you to become Heyyou
    • split with \\s+ that means sequence of space chars
  • groupingBy and counting to count occurence
  • Collectors.joining for the answer building part

public static String countWords(List<String> lines) {
    return lines.stream()
            .filter(l -> l.length() > 3)
            .map(l -> l.replaceAll("[,.!?]", " ").toLowerCase())
            .flatMap(l -> Arrays.stream(l.split("\\s+")))
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
            .entrySet()
            .stream()
            .filter(e -> e.getKey().length() >= 4 && e.getValue() >= 10)
            .sorted(Comparator.comparingLong(Map.Entry<String, Long>::getValue)
                    .reversed()
                    .thenComparing(Map.Entry::getKey)
            )
            .map(it -> it.getKey() + " - " + it.getValue())
            .collect(Collectors.joining("\n"));
}
azro
  • 53,056
  • 7
  • 34
  • 70
  • If there are 20 hello and 15 Hello, I should print 35 hello, that is why i need to convert it to lowercase –  Aug 07 '21 at 08:07
  • Oh thank you very much! Nice explanation. –  Aug 07 '21 at 08:09
  • 2
    Possibly it's worth to fix replacement and splitting part `Arrays.stream(l.replaceAll("[,.!?]", " ").split("\\s+"))` - replace with `" "` and split by asequence of white spaces. – Nowhere Man Aug 07 '21 at 08:10