Sort a list

This example will show how to sort an arraylist of objects using java, java 8 and guava. In the setup we will create a Wrestler class and initialize a list of wrestlers of varying weight, names and wins.

Setup

Wrestler class

public class Wrestler {

    private String name;
    private double weightClass;
    private int wins;

    public Wrestler(String name, double weightClass, int wins) {
        super();
        this.name = name;
        this.weightClass = weightClass;
        this.wins = wins;
    }

    public String getName() {
        return name;
    }

    public double getWeightClass() {
        return weightClass;
    }

    public int getWins() {
        return wins;
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this).add("name", name)
                .add("weightClass", weightClass).add("wins", wins)
                .toString();
    }
}

Initialize Wrestlers

private List<Wrestler> wrestlers = Lists.newArrayList();

@Before 
public void setup () {
    wrestlers.add(new Wrestler("Abe", 151, 5));
    wrestlers.add(new Wrestler("Steve", 151, 7));
    wrestlers.add(new Wrestler("Jack", 151, 1));
    
    wrestlers.add(new Wrestler("Jim", 215, 15));
    wrestlers.add(new Wrestler("Jack", 215, 1));
    wrestlers.add(new Wrestler("Joe", 215, 8));
    
    wrestlers.add(new Wrestler("Harry", 119, 6));
    wrestlers.add(new Wrestler("Sally", 119, 9));
}

Straight up Java

In this snippet we will sort a collection by a field using java. We will implement a Comparator naming it byWeightClass that will compare each wrestlers by weight class and pass it to Collections.sort which will sort the list according to the order defined in the comparator. After this operation is executed the list will be 'sorted by weight class' in ascending order.

@Test
public void sort_collection_with_java() {

    Comparator<Wrestler> byWeightClass = new Comparator<Wrestler>() {
        public int compare(Wrestler left, Wrestler right) {
            return Double.compare(left.getWeightClass(),
                    right.getWeightClass()); // use your logic
        }
    };

    Collections.sort(wrestlers, byWeightClass);

    logger.info(wrestlers);

    Wrestler wrestler = wrestlers.get(0);
    assertEquals(119, wrestler.weightClass, 0);
}

Output

[
    Wrestler{name=Harry, weightClass=119.0, wins=6}, 
    Wrestler{name=Sally, weightClass=119.0, wins=9}, 
    Wrestler{name=Abe, weightClass=151.0, wins=5}, 
    Wrestler{name=Steve, weightClass=151.0, wins=7}, 
    Wrestler{name=Jack, weightClass=151.0, wins=1}, 
    Wrestler{name=Jim, weightClass=215.0, wins=15}, 
    Wrestler{name=Jack, weightClass=215.0, wins=1}, 
    Wrestler{name=Joe, weightClass=215.0, wins=8}
]

Java 8

Order by number

In this snippet we will order the collection based off an integer field in the Wrestler object with java 8. Using a lambda expression we will create a comparator that will compare the weight of two given Wrestler objects. We will pass it into the List.sort method that will sort the list based on the supplied Comparator. Once the operation is performed the list of wrestlers will be sorted by weight class in ascending order.

@Test
public void sort_collection_with_java8_byweight() {

    wrestlers.sort((w1, w2) -> Double.compare(w1.getWeightClass(),
            w2.getWeightClass()));

    logger.info(wrestlers);

    Optional<Wrestler> wrestler = wrestlers.stream().findFirst();

    assertEquals(119, wrestler.get().getWeightClass(), 0);
}

Output

[
    Wrestler{name=Harry, weightClass=119.0, wins=6}, 
    Wrestler{name=Sally, weightClass=119.0, wins=9}, 
    Wrestler{name=Abe, weightClass=151.0, wins=5}, 
    Wrestler{name=Steve, weightClass=151.0, wins=7}, 
    Wrestler{name=Jack, weightClass=151.0, wins=1}, 
    Wrestler{name=Jim, weightClass=215.0, wins=15}, 
    Wrestler{name=Jack, weightClass=215.0, wins=1}, 
    Wrestler{name=Joe, weightClass=215.0, wins=8}
]

Reverse order

This snippet will sort a collection in descending order with java 8. We will create a Comparator field from a lambda expression and call reverse which will imposes the reverse ordering of this comparator. Then calling the List.sort method we will sort the list of wrestlers by weight class in reverse order.

@Test
public void sort_collection_with_java8_byweight_reverse () {

    Comparator<Wrestler> normal = ((w1, w2) -> Double.compare(
            w1.getWeightClass(), w2.getWeightClass()));
    Comparator<Wrestler> reversed = normal.reversed(); 
    
    wrestlers.sort(reversed);
    
    logger.info(wrestlers);

    Optional<Wrestler> wrestler = wrestlers.stream().findFirst();
    
    assertEquals(215, wrestler.get().getWeightClass(), 0);
}

Output

[
    Wrestler{name=Jim, weightClass=215.0, wins=15}, 
    Wrestler{name=Jack, weightClass=215.0, wins=1}, 
    Wrestler{name=Joe, weightClass=215.0, wins=8}, 
    Wrestler{name=Abe, weightClass=151.0, wins=5}, 
    Wrestler{name=Steve, weightClass=151.0, wins=7}, 
    Wrestler{name=Jack, weightClass=151.0, wins=1},
    Wrestler{name=Harry, weightClass=119.0, wins=6}, 
    Wrestler{name=Sally, weightClass=119.0, wins=9}
]

Order by string

This snippet will show how to sort a collection of object by string field with java 8. Using a lambda expression we will create a comparator that will compare the name of two given Wrestler objects. We will pass it into the List.sort method that will sort the list based on the supplied Comparator. Once the operation is performed the list of wrestlers will be sorted by name in ascending order.

@Test
public void sort_collection_with_java8_byname () {
    
    wrestlers.sort((w1, w2) -> w1.getName().compareTo(w2.getName()));

    logger.info(wrestlers);

    Optional<Wrestler> wrestler = wrestlers.stream().findFirst();
    
    assertEquals("Abe", wrestler.get().getName());
}

Output

[
    Wrestler{name=Abe, weightClass=151.0, wins=5}, 
    Wrestler{name=Harry, weightClass=119.0, wins=6}, 
    Wrestler{name=Jack, weightClass=151.0, wins=1}, 
    Wrestler{name=Jack, weightClass=215.0, wins=1}, 
    Wrestler{name=Jim, weightClass=215.0, wins=15}, 
    Wrestler{name=Joe, weightClass=215.0, wins=8}, 
    Wrestler{name=Sally, weightClass=119.0, wins=9}, 
    Wrestler{name=Steve, weightClass=151.0, wins=7}
]

Chaining multiple comparators

This snippet will demonstrate how to sort the collection on multiple fields or chain multiple comparators using java 8. We will first sort the collection of wrestlers by weight class then by the number of wins by passing in two comparators created by a lambda expression.

@Test
public void sort_collection_with_java8_byweight_wins() {

    List<Wrestler> sorted = wrestlers
            .stream()
            .sorted((w1, w2) -> Double.compare(w1.getWeightClass(),
                    w2.getWeightClass()))
            .sorted((w1, w2) -> Integer.compare(w1.getWins(), w2.getWins()))
            .collect(Collectors.toList());

    logger.info(sorted);

    Optional<Wrestler> wrestler = sorted.stream().findFirst();

    assertEquals(151, wrestler.get().getWeightClass(), 0);
}

Output

[
    Wrestler{name=Jack, weightClass=151.0, wins=1}, 
    Wrestler{name=Jack, weightClass=215.0, wins=1}, 
    Wrestler{name=Abe, weightClass=151.0, wins=5}, 
    Wrestler{name=Harry, weightClass=119.0, wins=6}, 
    Wrestler{name=Steve, weightClass=151.0, wins=7}, 
    Wrestler{name=Joe, weightClass=215.0, wins=8}, 
    Wrestler{name=Sally, weightClass=119.0, wins=9}, 
    Wrestler{name=Jim, weightClass=215.0, wins=15}
]

Google Guava

Guava's ordering class is an enhanced comparator, with additional methods to support common operations. If are familiar with the FluentIterable, FluentIterable is to Iterable as Ordering is to comparator.

Ordering

This snippet will show how to sort a list of strings in alphabetical order with Guava. First byName Ordering object is created and passed to the Collections.sort which will sort the array list in ascending order.

static final Ordering<Wrestler> byName = new Ordering<Wrestler>() {
    public int compare(Wrestler left, Wrestler right) {
        return left.getName().equals(right.getName()) ? 1 : 0;
    }
};

@Test
public void display_wrestlers_by_weightclass_and_in_alphabetical_order () {

    Collections.sort(wrestlers, byName);
    
    logger.info(wrestlers);
    
    Wrestler firstAlphabetically  = Iterables.getFirst(wrestlers, null);
    
    assertNotNull(firstAlphabetically);
    assertEquals("Abe", firstAlphabetically.getName());
}

Output

[
    Wrestler{name=Abe, weightClass=151.0, wins=5}, 
    Wrestler{name=Steve, weightClass=151.0, wins=7}, 
    Wrestler{name=Jack, weightClass=151.0, wins=1}, 
    Wrestler{name=Jim, weightClass=215.0, wins=15}, 
    Wrestler{name=Jack, weightClass=215.0, wins=1}, 
    Wrestler{name=Joe, weightClass=215.0, wins=8}, 
    Wrestler{name=Harry, weightClass=119.0, wins=6}, 
    Wrestler{name=Sally, weightClass=119.0, wins=9}
]

Ordering in reverse

This snippet will sort the collection from highest to lowest with Guava. Creating a Ordering object byWeightClass and passing it into Collections.Sort will sort the wrestlers in descending order.

static final Ordering<Wrestler> byWeightClass = new Ordering<Wrestler>() {
    public int compare(Wrestler left, Wrestler right) {
        return Doubles.compare(left.getWeightClass(),
                right.getWeightClass());
    }
};

@Test
public void sort_collection_in_reverse_with_guava() {

    Collections.sort(wrestlers, byWeightClass.reverse());

    logger.info(wrestlers);

    Wrestler aWrestlerWithHighestWeightClass = Iterables.getFirst(
            wrestlers, null);

    assertNotNull(aWrestlerWithHighestWeightClass);
    assertEquals(215, aWrestlerWithHighestWeightClass.getWeightClass(), 0);
}

Output

[
    Wrestler{name=Jim, weightClass=215.0, wins=15}, 
    Wrestler{name=Jack, weightClass=215.0, wins=1}, 
    Wrestler{name=Joe, weightClass=215.0, wins=8}, 
    Wrestler{name=Abe, weightClass=151.0, wins=5}, 
    Wrestler{name=Steve, weightClass=151.0, wins=7}, 
    Wrestler{name=Jack, weightClass=151.0, wins=1}, 
    Wrestler{name=Harry, weightClass=119.0, wins=6}, 
    Wrestler{name=Sally, weightClass=119.0, wins=9}
]

Chaining multiple ordering

This snippet will chain multiple Ordering objects by calling the compound method. First it will be sorted by weightClass then by wins.

static final Ordering<Wrestler> byWins = new Ordering<Wrestler>() {
    public int compare(Wrestler left, Wrestler right) {
        return Ints.compare(left.getWins(), right.getWins());
    }
};

@Test
public void sort_collection_with_multiple_comparables_guava() {

    Collections.sort(wrestlers, byWeightClass.compound(byWins));

    logger.info(wrestlers);

    Wrestler aLowestWeightClassWrestler = Iterables.getFirst(wrestlers,
            null);

    assertNotNull(aLowestWeightClassWrestler);
    assertEquals(119, aLowestWeightClassWrestler.getWeightClass(), 0);

}

Output

[
    Wrestler{name=Harry, weightClass=119.0, wins=6}, 
    Wrestler{name=Sally, weightClass=119.0, wins=9}, 
    Wrestler{name=Jack, weightClass=151.0, wins=1}, 
    Wrestler{name=Abe, weightClass=151.0, wins=5}, 
    Wrestler{name=Steve, weightClass=151.0, wins=7}, 
    Wrestler{name=Jack, weightClass=215.0, wins=1}, 
    Wrestler{name=Joe, weightClass=215.0, wins=8}, 
    Wrestler{name=Jim, weightClass=215.0, wins=15}
]

Multiple ordering & .getFirst

Finally this snippet will display top wrestlers in each weight class.

@Test
public void sort_collection_with_multiple_comparables_guava_getfirstElement() {

    // first order elements
    Collections.sort(wrestlers, byWeightClass.compound(byWins.reverse()));

    // next get the first wrestler in each weight class which should have
    // the most wins
    ImmutableListMultimap<Double, Wrestler> wrestlersMappedByWeightClass = Multimaps
            .index(wrestlers, new Function<Wrestler, Double>() {
                public Double apply(Wrestler from) {
                    return new Double(from.getWeightClass());
                }
            });

    logger.info(wrestlersMappedByWeightClass);

    // for each weight class get the first element which should be wrestler
    // with most wins
    for (Double weightClass : wrestlersMappedByWeightClass.keySet()) {

        List<Wrestler> weightClassWrestlers = wrestlersMappedByWeightClass
                .get(weightClass);
        logger.info(weightClass + " - "
                + Iterables.getFirst(weightClassWrestlers, null));
    }
}

Output

119.0 - Wrestler{name=Sally, weightClass=119.0, wins=9}
151.0 - Wrestler{name=Steve, weightClass=151.0, wins=7}
215.0 - Wrestler{name=Jim, weightClass=215.0, wins=15}