Code Bug Fix: Sort list of strings by multiple parameters

Original Source Link

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?

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()));

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!

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?

Tagged : / /

Leave a Reply

Your email address will not be published. Required fields are marked *