Home > Mobile >  How to Sort a list of objects based on two date fields
How to Sort a list of objects based on two date fields

Time:10-25

I am trying to sort a list of objects in Java. Each object contains two date fields Date1 and Date2. If Date1 is not null then Date2 should be null and if Date2 is not null then Date1 should be null. Let's say Our class name is Product and we have a list inventoryList of object products.

products :[
           {
             "name":"abc",
             ...,
             "Date1": "2021-04-18 10:36:34 PM",
             ..., 
             "Date2":"null",
             ...
           },
            "name":"def",
             ...,
             "Date1": "null",
             ...,
             "Date2":"2021-05-17 11:26:34 PM",
             ...
           ]

I want to sort this list with respect to either of the date of the object in descending order. Thanks in advance.

CodePudding user response:

You can use the Comparator.comparing() method to specify the property to sort in a lambda expression.

record Product(String name, LocalDate Date1, LocalDate Date2) {}

List<Product> products = Arrays.asList(
    new Product("abc", LocalDate.of(2021, 4, 18), null),
    new Product("def", null, LocalDate.of(2021, 5, 17)));

products.sort(Collections.reverseOrder(
    Comparator.comparing(p -> p.Date1() != null ? p.Date1() : p.Date2())));

products.stream()
    .forEach(System.out::println);

output:

Product[name=def, Date1=null, Date2=2021-05-17]
Product[name=abc, Date1=2021-04-18, Date2=null]

CodePudding user response:

You can try using the below approach for sorting the data based on dates using stream.

Here, I have used dates in the LocalDateTime format instead of String.

public class Test {
    public static void main(String[] args) throws ParseException {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss a", Locale.ENGLISH);
        Product p1 = new Product("abc", LocalDateTime.parse("2021-04-18 10:36:34 PM",formatter),null);
        Product p2 = new Product("def",null,LocalDateTime.parse("2021-05-17 11:26:34 PM",formatter));

        List<Product> sortedList = Stream.of(p1,p2)
                .sorted(Comparator.comparing(x -> x.getDate1()!=null ? x.getDate1():x.getDate2(),
                        Comparator.nullsFirst(Comparator.reverseOrder())))
                .collect(Collectors.toList());

        System.out.println(sortedList);
    }
}

Product.java

public class Product {

    private String name;
    private LocalDateTime date1;
    private LocalDateTime date2;

    public Product(String name, LocalDateTime date1, LocalDateTime date2) {
        this.name = name;
        this.date1 = date1;
        this.date2 = date2;
    }
    
    //getters and setters
}

Output:

[Product{name='def', date1=null, date2=2021-05-17T23:26:34},
 Product{name='abc', date1=2021-04-18T10:36:34, date2=null}]

CodePudding user response:

I suggest you to handle the choosing date logic inside Product class like this

import java.util.Date;

public class Product {
    private String name;
    private Date dateOne;
    private Date dateTwo;

    public Product(String name, Date dateOne, Date dateTwo) {
        this.name = name;
        this.dateOne = dateOne;
        this.dateTwo = dateTwo;
    }

    public Date getDate() {
        if (this.dateOne != null) {
            return dateOne;
        }
        return dateTwo;
    }

}

Then in the Inventory class you can sort like this

public class Inventory {
    public List<Product> sort(List<Product> products) {
        products.sort((Product productOne, Product productTwo) -> {
                if (productOne.getDate().before(productTwo.getDate())) {
                    return -1;
                } else if (productOne.getDate().after(productTwo.getDate())) {
                    return 1;
                } else {
                    return 0;
                }
        });

      return products;
    }
}

CodePudding user response:

You can use List.sort(Comparator<? super E>) to sort a list in situ, providing a Comparator - an instruction of how two Products would've been compared:

products.sort((x, y) -> {/* logics */})

And now you can compare on x and y i.e. get and compare their dates, do null checks, etc., and return an integer whose signum tells if x is greater or smaller in order than y.

CodePudding user response:

If you want to use Streams, and you are not able to change the Product-class you can implement your own Comparator and use this in the Stream-logic.

Comparator-Example:

public class ProductComparator implements Comparator<Product> {

    @Override
    public int compare(Product product1, Product product2) {
        String product1Date = product1.getDate1() != null ? product1.getDate1() : product1.getDate2();
        String product2Date = product2.getDate1() != null ? product2.getDate1() : product2.getDate2();

        return product1Date.compareTo(product2Date);
    }
}

The sorting with Streams could then look like this:

List<Product> productListSorted = productList.stream()
                .sorted(new ProductComparator())
                .collect(Collectors.toList());

If you just want to sort the list itself, you can use:

productList.sort(new ProductComparator());

Be aware that this Comparator will throw a NullPointerException if both Dates are null.

CodePudding user response:

You can use a collection with a custom comparator to sort. Inside the custom comparator, I checked for which date was not null and then returned the comparison.

class Product {
    private String name;
    private String date1;
    private String date2;
    
    public Product(String name, String date1, String date2) {
        this.name = name;
        this.date1 = date1;
        this.date2 = date2;
    }
    public String getName() {
        return this.name;
    }
    public String getDate1() {
        return this.date1;
    }
    public String getDate2() {
        return this.date2;
    }
}

public class SortProductsByDate {
    
    public static void main(String[] args) {
        List<Product> inventoryList = new ArrayList<>();
        inventoryList.add(new Product("abc", "2021-04-18 10:36:34 PM", null));
        inventoryList.add(new Product("def", null, "2021-05-17 11:26:34 PM"));
        
        Collections.sort(inventoryList, new Comparator<Product>() {
            @Override
            public int compare(Product p1, Product p2) {
                String d1 = p1.getDate1() == null ? p1.getDate2() : p1.getDate1();
                String d2 = p2.getDate1() == null ? p2.getDate2() : p2.getDate1();
                
                return d2.compareTo(d1);
            }
            });
        
        for(Product p : inventoryList) {
            System.out.printf("name: %s\nDate1: %s\nDate2: %s\n\n", p.getName(), p.getDate1(), p.getDate2());
        }
    }
}

Console Output:

name: def
Date1: null
Date2: 2021-05-17 11:26:34 PM

name: abc
Date1: 2021-04-18 10:36:34 PM
Date2: null

You can also separate the logic even further and clean up the main method. Implement the comparator within Product class and create a separate class for ProductInventory. Also keep in mind when you override compareTo() that you should also take care of equals() and hashcode() method as well to avoid any issues. I auto-generated those fields within the IDE.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

class Product implements Comparable<Product>{
    private String name;
    private String date1;
    private String date2;
    
    public Product(String name, String date1, String date2) {
        this.name = name;
        this.date1 = date1;
        this.date2 = date2;
    }
    
    public String getName() {
        return this.name;
    }
    
    public String getDate1() {
        return this.date1;
    }
    
    public String getDate2() {
        return this.date2;
    }
    
    @Override
    public int compareTo(Product other) {
        String thisDate = this.getDate1() == null ? this.getDate2() : this.getDate1();
        String otherDate = other.getDate1() == null ? other.getDate2() : other.getDate1();
        return otherDate.compareTo(thisDate);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(date1, date2, name);
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Product other = (Product) obj;
        return Objects.equals(date1, other.date1) 
                && Objects.equals(date2, other.date2)
                && Objects.equals(name, other.name);
    }
    
    @Override
    public String toString() {
        String date = date1 == null ? date2 : date1;
        return "[name:"   name   ", date="   date   "]";
    }
}

class ProductInventory {
    private List<Product> inventoryList;
    
    public ProductInventory() {
        this.inventoryList = new ArrayList<Product>();
    }
    
    public List<Product> getInventoryList() {
        return this.inventoryList;
    }
    
    public void add(Product p) {
        this.inventoryList.add(p);
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for(Product p : inventoryList) {
            sb.append(p.toString());
            sb.append("\n");
        }
        return sb.toString();
    }
}
public class SortProductsByDateDescending {
    
    public static void main(String[] args) {        
        ProductInventory productInventory = new ProductInventory();
        
        productInventory.add(new Product("abc", "2021-04-18 10:36:34 PM", null));
        productInventory.add(new Product("def", null, "2022-03-08 03:30:24 AM"));
        productInventory.add(new Product("ghi", null, "2021-05-17 11:26:34 PM"));
        productInventory.add(new Product("jkl", "2025-01-22 01:33:16 AM", null));
        productInventory.add(new Product("mno", "2025-01-22 01:33:16 PM", null));
        productInventory.add(new Product("pqr", "2025-01-22 01:33:17 PM", null));
        
        Collections.sort(productInventory.getInventoryList());
        System.out.println(productInventory.toString());
    }
}

Console Output:

[name:pqr, date=2025-01-22 01:33:17 PM]
[name:mno, date=2025-01-22 01:33:16 PM]
[name:jkl, date=2025-01-22 01:33:16 AM]
[name:def, date=2022-03-08 03:30:24 AM]
[name:ghi, date=2021-05-17 11:26:34 PM]
[name:abc, date=2021-04-18 10:36:34 PM]
  • Related