2

I'm considering how to sort an ArrayList with two parameters. First by occurences of some char in string, then by natural order. Here is the code:

  ArrayList<String> words;
    words=getWords(sentence);//return all words from sentence
    words.sort(Comparator.comparing(o -> countChar(c,  o))
                     .thenComparing(Comparator::naturalOrder));

Method getWords(sentence) return an ArrayList<String> of words from sentence.

Method countChar(c,o) counts number of char c in word o.

When adding .thenComparing(Comparator::naturalOrder)) IDE shows that o should be cast to String and that it can't resolve method thenComparing().

What might be the problem?

Andrei Yusupau
  • 587
  • 1
  • 11
  • 30
  • Does this answer your question? [Is it possible to Generate a thumbnail from a video url in android](https://stackoverflow.com/questions/22954894/is-it-possible-to-generate-a-thumbnail-from-a-video-url-in-android) – DallaRosa May 15 '20 at 09:25

3 Answers3

4

Two mistakes in your code.

  1. You'll need to provide the generic parameters to comparing
  2. naturalOrder returns a comparator; invoke it, rather than passing a reference

Try:

        words.sort(Comparator.<String, Integer>comparing(o -> countChar(c,  o))
                         .thenComparing(Comparator.naturalOrder()));

Joe
  • 29,416
  • 12
  • 68
  • 88
  • It compiles fine. Could you please tell me why are we providing `Comparator.<>` than `Comparator<>.`. I am poor in generics :( – Gibbs May 15 '20 at 09:22
  • See https://stackoverflow.com/questions/27166610/what-does-the-dot-operator-before-the-generic-parameter-mean – Joe May 15 '20 at 09:25
  • 1
    Great answer! Added `.reversed()` as elements with occurences of char `c` should go first and than elements in natural order: ```words.sort(Comparator.comparing(o -> countChar(c, o)).reversed().thenComparing(Comparator.naturalOrder()));``` – Andrei Yusupau May 15 '20 at 09:27
1

My solution is to add an object with count(c) and impl the Comparable.

class StringWithChar implements Comparable<StringWithChar> {
    private String s;
    private char c;
    private long count;
    public StringWithChar(String s, char c) {
         this.s = s;
         this.c = c;
         count = s.chars().filter(ch -> ch == c).count();
     }

     public String getS() {
         return s;
     }

     public void setS(String s) {
         this.s = s;
     }

     public char getC() {
         return c;
     }

     public void setC(char c) {
         this.c = c;
     }

     public long getCount() {
         return count;
     }

     public void setCount(long count) {
         this.count = count;
     }

     @Override
     public int compareTo(StringWithChar s2) {
         int res = Long.compare(this.getCount(), s2.getCount());
         if (res == 0) {
             return this.getS().compareTo(s2.getS());
         }
         return res;
     }
 }

// then you can easier stream 
words.stream().map(s -> new StringWithChar(s, c)).sort().collect(Collectors.toList());

I hope it helps!

PatrickChen
  • 1,350
  • 1
  • 11
  • 19
  • `class StringWithChar implements Comparator` are you possibly confusing [`Comparable` and `Comparator`](https://stackoverflow.com/questions/2266827/when-to-use-comparable-and-comparator/31244596)? – Joe May 15 '20 at 09:23
0

My only concern with that approach is a potential performance bottle neck as it could potentially loop through all elements to sort by the first comparator then loop again to sort by the 2nd comparator.
Perhaps try creating a single comparator that does both comparisons and use that instead?

fpezzini
  • 774
  • 1
  • 8
  • 17
  • 1
    list will be sort by a single - combined - comparator. No need to worry about list being traversed twice... – dpr May 15 '20 at 09:22
  • This approach works, but I expected usage of Java 8 will make it look better :) ```words.sort((s1, s2) -> { int charCount; charCount = Integer.compare(countChar(c, s2), countChar(c, s1)); if (charCount != 0) { return charCount; } return s1.compareTo(s2); });``` – Andrei Yusupau May 15 '20 at 09:31