How to sort a List by checking a value inside inner list in Java?

Viewed 63

I have a class like the following,

public class Inventory {

   private String name;
   private List<Sample> samples;
}

public class Sample {

   private int count;
   private String date;
}

List<Inventory> inventories;

I have sorted the samples by date. It's fine. But I need to sort the inventories list by date field inside Sample class. samples are already sorted. So I need the inventories to sort by samples date DESC. For example,

Inside that inventories list, if it has 3 data,

Inventory 1
name = 1
samples has dates of = List of (2021-07-02, 2021-07-03)

Inventory 2
name = 2
samples has dates of = List of (2021-07-02, 2021-09-03, 2021-10-03)

Inventory 3
name = 3
samples has dates of = List of (2021-08-02, 2021-09-03)

So it should sort by date DESC and in that inventories list, it should have the data following way,

Inventory 1
Inventory 3
Inventory 2
2 Answers

You want to sort collections based on the values in nested collections. How do we do it?

You need to implement a custom comparator to do this ...

static class InventoryComparator implements Comparator<Inventory> {
     public int compare(Inventory i1, Inventory i2) {
         // compare them here like this 
         // a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
         // this can be done by checking the nested lists
     }
}

Then you can sort your collection like this ...

Collections.sort(inventoryList, new InventoryComparator());

This is possible with the Comparable interface.

I have assumed that the Sample objects are sorted by date and Inventory objects are sorted by comparing the last (Sample with latest date) Sample in samples, but you can implement your own custom comparing logic in Samples overridden compareTo() method.

  public class Inventory implements Comparable<Inventory> {

    private String name;
    private List<Sample> samples;

    public List<Sample> getSamples() {
      return samples;
    }

    public Inventory(String name, List<Sample> samples) {
      this.name = name;
      this.samples = samples;
    }

    @Override
    public int compareTo(Inventory inventory) {
      Optional<Sample> thisOldestSample = this.getSamples().stream().sorted().reduce((s1, s2) -> s2);
      Optional<Sample> thatOldestSample = inventory.getSamples().stream().sorted().reduce((s1, s2) -> s2);

      if (thisOldestSample.isPresent() && thatOldestSample.isPresent()) {
        return thisOldestSample.get().compareTo(thatOldestSample.get());
      } else {
        return 0;
      }
    }
  }

  public class Sample implements Comparable<Sample> {

    private int count;
    private String date;

    public String getDate() {
      return date;
    }

    public Sample(int count, String date) {
      this.count = count;
      this.date = date;
    }

    @Override
    public int compareTo(Sample sample) {
      return LocalDate.parse(sample.getDate()).isBefore(LocalDate.parse(this.getDate())) ? 1 : -1;
    }
  }

  @Test
  void shouldSortInventoriesBasedOnSampleDate() {
    Inventory one = new Inventory("1", List.of(new Sample(0, "2021-07-02"), new Sample(1, "2021-07-03")));
    Inventory two = new Inventory("2", List.of(new Sample(0, "2021-07-02"), new Sample(1, "2021-09-03"), new Sample(2, "2021-10-03")));
    Inventory three = new Inventory("3", List.of(new Sample(0, "2021-08-02"), new Sample(1, "2021-09-03")));

    List<Inventory> unsorted  = List.of(one, two, three);
    List<Inventory> sorted = unsorted.stream().sorted().collect(Collectors.toList());

    assertEquals(one, sorted.get(0));
    assertEquals(three, sorted.get(1));
    assertEquals(two, sorted.get(2));
  }
Related