1

I have a problem with sorting the letters of a word, by the number of occurrences of the letters and if the letters appear the same number of times, it will be sorted at least lexicographically. I have a code but I get compilation error on the site and 0 points because they use java 7 and I don't know how to solve the last part of the problem without "lambda".

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class prog {
    public static void main(String[] args) throws IOException {
        String testString = " ";
        BufferedReader rd = new BufferedReader(new InputStreamReader(System.in));
        testString = rd.readLine();
        Map < Character, List < Character >> map = new HashMap < > ();
        for (int i = 0; i < testString.length(); i++) {
            char someChar = testString.charAt(i);
            if (someChar == ' ') {
                continue;
            }
            char ch = testString.charAt(i);
            List < Character > characters =
                map.getOrDefault(Character.toLowerCase(ch), new ArrayList < > ());
            characters.add(ch);
            map.put(Character.toLowerCase(ch), characters);
        }
        List < Map.Entry < Character, List < Character >>> list =
            new ArrayList < > (map.entrySet());

        list.sort((o1, o2) - > {
            if (o1.getValue().size() == o2.getValue().size()) {
                return o1.getKey() - o2.getKey();
            }
            return o2.getValue().size() - o1.getValue().size();
        });
        list.forEach(entry - > entry.getValue().forEach(System.out::print));
    }
}
Miss Chanandler Bong
  • 4,081
  • 10
  • 26
  • 36
STRKLok
  • 29
  • 1
  • What site? Can't you just choose which java version you want to use? – Amongalen Feb 24 '20 at 13:48
  • Anyway, you will have to implement your own `Comparator`, use `Collections.sort()` and rewrite `forEach` as a simple loop. And change the part with `map.getOrDefault` as well. – Amongalen Feb 24 '20 at 13:52
  • Java 8 is old hat by now. You should report it to the site. They are doing their patrons a disservice by not supporting it and future, stable, releases. – WJS Feb 24 '20 at 15:05
  • @STRKLok You may want to rethink returning subtracted values in your `comparator` implementation. It doesn't always work and can lead to pitfalls. It is best to return explicit values of 1, -1, or 0 as appropriate. – WJS Feb 24 '20 at 16:06

2 Answers2

2

You can use Collections.sort(List<T> list, Comparator<? super T> c):

Collections.sort(list, new Comparator<Map.Entry<Character, List<Character>>>() {
    @Override
    public int compare(Map.Entry<Character, List<Character>> o1, Map.Entry<Character, List<Character>> o2) {
        if (o1.getValue().size() == o2.getValue().size()) {
            return o1.getKey() - o2.getKey();
        }
        return o2.getValue().size() - o1.getValue().size();
    }
});

for (Map.Entry<Character, List<Character>> characterListEntry : list) {
    System.out.println(characterListEntry);
}

Map#getOrDefault(Object key, V defaultValue) was also introduced in Java 8. you need to change it to something like:

char cKey = Character.toLowerCase(ch);
List<Character> characters = map.containsKey(cKey) ? map.get(cKey) : new ArrayList<>();
Miss Chanandler Bong
  • 4,081
  • 10
  • 26
  • 36
0

To build the map with Java 7 you can do it as follows.

        // convert to lower case from the start
        testString = rd.readLine().toLowerCase();

        Map<Character, List<Character>> map = new HashMap<>();
        for (int i = 0; i < testString.length(); i++) {
            char someChar = testString.charAt(i);
            if (someChar == ' ') {
                continue;
            }
            // try and get the list
            List<Character> characters = map.get(someChar);
            if (characters == null) {
                // otherwise, create it
                characters = new ArrayList<>();
                // and put it in the map
                map.put(someChar, characters);
            }
            // add characters to the obtained list.
            characters.add(someChar);
        }

For the Comparator and other similar implementations, I prefer to use `local classes. Imo they are cleaner than anonymous classes but do require additional syntax. If you aren't familiar with these, this would go inside your main class.


    static class CountThenLex implements
                Comparator<Entry<Character, List <Character>>> {
        public int compare(
            Entry<Character, List<Character>> a,
            Entry<Character, List <Character>> b) {
            int asize = a.getValue().size();
            int bsize = b.getValue().size();
            // note that b is sorted first for descending count order.

            int aTob = bsize > asize ? 1 :
                bsize < asize ? -1 : 0;
            if (aTob != 0) {
                return aTob;
            }

            // if the counts are equal, then sort lexically.  Since the Character
            // class implements `Comparable` you can use the natural ordering.
            return a.getKey().compareTo(b.getKey());
        }
    }

Then you just call sort with an instance of the class.

    Collections.sort(list, new CountThenLex());

You will also have to modify your print method as well as other methods since other Java 8 features are also present. Here is the basic print solution.

    for(Entry<?,List<Character>> e : list) {
        for (char c : e.getValue()) {
            System.out.print(c);
        }
    }
    System.out.println();
WJS
  • 36,363
  • 4
  • 24
  • 39