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]