Сортировка объектов по полю с дополнительной логикой

Есть класс Word, у него есть поле String word. Создаем список из объектов List<Word> words.

Нужно отсортировать объекты по количеству вхождений определенной буквы в поле String Word word.

Подскажите, как лучше отсортировать такой список? Comparable и Comparator здесь не подходят (ну или я не понял как), т.к. буква, по которой нужно сортировать заранее не известна, и нам еще нужно подсчитать ее количество в каждом слове.

public class Word {

    private final String word;

    public Word(String word) {
        this.word = word;
    }

    public String getWord() {
        return word;
    }

}

Ответы (2 шт):

Автор решения: default locale

Для начала можно написать метод, который считает количество вхождений буквы в Word:

/**
* Подсчет количества вхождений буквы в слово
*/
static int countLetter(Word word, char letter) {
     String w = word.word;
     return w.length() - w.replace(letter + "", "").length();
}

Затем его можно использовать и в компараторе с методом sort:

words.sort((Word o1, Word o2) -> {
            int c1 = countLetter(o1, 'a');
            int c2 = countLetter(o2, 'a');
            return Integer.compare(c1, c2);
        });

И со стримами, если нужно:

List<Word> sortedWords = words.stream()
    .sorted(Comparator.comparing(w -> countLetter(w, 'a')))
    .collect(Collectors.toList());

Оба метода могут рассчитывать количество более одного раза для одного слова. Если количество слов будет огромным и возникнут проблемы с производительностью, то может потребоваться предварительно рассчитать количество вхождений для каждого слова (создать для этого отдельный массив/класс/пару значений).

→ Ссылка
Автор решения: Qwertiy

Если для производительности некритично вычисление числа вхождений буквы при каждом сравнении, то нужно просто сделать букву полем компаратора и внутри метода сравнения выполнять подсчёт.

Если нужно сделать более оптимально, то создаём массив пар ссылка, количество. Компаратор по-прежнему получает букву в конструкторе, но обращается к уже посчитанному количеству вхождений. А после сортировки проходим по новому массиву и из него присваиваем элементы в оригинальный.

При желании вместо передачи в конструктор можно использовать замыкание.

→ Ссылка