Start learning free

LESSON 264 OF 671 · RECORDS, SORTING & BUILT-INS

Shortest Words First in Java: Sorting with a Lambda

Practice Read the full explanation

You get an ArrayList of words, words. Return the words sorted from shortest to longest.

Words of the same length go in alphabetical order, from A to Z.

A word can appear more than once. Every copy stays in the result.

 

Example 1:

Input: words = ["banana", "fig", "apple", "kiwi"]
Output: ["fig", "kiwi", "apple", "banana"]
Explanation: "fig" has 3 letters and "kiwi" has 4.
"apple" has 5 and "banana" has 6.

Example 2:

Input: words = ["dog", "cat", "ant", "bee"]
Output: ["ant", "bee", "cat", "dog"]
Explanation: All four words have 3 letters.
So they go from A to Z.

Example 3:

Input: words = ["sun", "a", "moon", "sun"]
Output: ["a", "sun", "sun", "moon"]
Explanation: "sun" appears twice, so it stays twice.
Both copies come after "a" and before "moon".

 

Constraints:

  • words has 1 to 100 words.
  • Each word has 1 to 20 lowercase letters.
STEP 1 OF 3
    Ctrl + Enter to check

    JAVA · RECORDS, SORTING & BUILT-INS

    Shortest Words First in Java, explained

    Problem overview

    The method sortByLength gets a list of words and returns it sorted from shortest to longest. Words of the same length go in alphabetical order, and repeated words all stay.

    For ["banana", "fig", "apple", "kiwi"] the result is [fig, kiwi, apple, banana]. For ["dog", "cat", "ant", "bee"] every word has 3 letters, so it is just alphabetical: [ant, bee, cat, dog]. For ["sun", "a", "moon", "sun"] the result is [a, sun, sun, moon].

    Approach: a sort with two rules

    List.sort takes a comparator, a function of two items a and b that returns a number. A negative number means a goes first, a positive number means b goes first, and 0 means they tie. Here the comparator has two rules in order: compare lengths, and only if the lengths are equal compare the words themselves.

    Step by step

    1. Call words.sort with a lambda (a, b) -> { ... } that has a body in braces. First rule: if a.length() != b.length(), return a.length() - b.length(). A shorter a gives a negative number, so it goes first.
    2. Second rule, for equal lengths: return a.compareTo(b). For strings this is alphabetical order (lowercase letters here).
    3. Return words. sort reorders the list itself and returns nothing, so the sorted list is the one you already have.

    What the comparator returns

    The sign of the number is all that matters. With a.length() - b.length(), comparing "fig" (a) with "kiwi" (b) returns -1, so "fig" goes first. Comparing "kiwi" with "fig" returns 1, and comparing two 3-letter words returns 0. Only that 0 case reaches the second rule.

    The sort is stable: words that compare as equal keep their original relative order. With the length rule alone, ["dog", "cat", "ant", "bee"] comes out unchanged as [dog, cat, ant, bee]. The second rule is what puts them in A to Z order.

    Because the comparator is an ordinary lambda, you can flip a rule by swapping a and b. For example, b.length() - a.length() alone turns the first example into [banana, apple, kiwi, fig].

    The solution in Java

    class Solution {
        public List<String> sortByLength(List<String> words) {
            words.sort((a, b) -> {
                if (a.length() != b.length()) {
                    return a.length() - b.length();
                }
                return a.compareTo(b);
            });
            return words;
        }
    }
    

    Subtracting lengths is safe, because lengths are small and never overflow. For arbitrary int values, subtraction can overflow, and Integer.compare(x, y) is the safer choice.

    Edge cases and common mistakes

    • Sorting changes the input list. The method sorts words in place. A list made by List.of(...) can't be reordered, and calling sort on it throws UnsupportedOperationException.
    • Forgetting the tie rule. With only the length rule, equal-length words are left in whatever order they were in, so dog, cat, ant, bee would not come out alphabetical.
    • Reversed subtraction. b.length() - a.length() sorts longest first.
    • Repeated words. compareTo returns 0 for two equal words and the sort keeps both. Nothing is removed.

    Testing

    Check your method on these lists. The results below are what the reference solution returns:

    • ["banana", "fig", "apple", "kiwi"] gives [fig, kiwi, apple, banana].
    • ["dog", "cat", "ant", "bee"] gives [ant, bee, cat, dog].
    • ["sun", "a", "moon", "sun"] gives [a, sun, sun, moon].

    A single word comes back unchanged. A longer word can be alphabetically earlier than a shorter one, such as "apple" against "fig". The result still puts "fig" first, because length is checked before the letters.

    Sorting a list of n words takes about n log n comparisons, and each comparison here looks at two lengths and, on a tie, at the letters of two short words. With at most 100 words of at most 20 letters, this is instant.

    Keep going with Java500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free