Please help with sorting in Java. I have a simple example (looks like this). I need to sort list by the difference between two BigDecimals.
My Data class (I cut getters)
public class Quotation {
private final long id;
private final BigDecimal askPrice;
private final BigDecimal bidPrice;
public Quotation(long id, BigDecimal bidPrice, BigDecimal askPrice) {
this.id = id;
this.askPrice = askPrice;
this.bidPrice = bidPrice;
}
}
Here we store our records.
storeQuotation(new Quotation(1000,new BigDecimal("99"), new BigDecimal("104")));
storeQuotation(new Quotation(1001,new BigDecimal("69"), new BigDecimal("72")));
storeQuotation(new Quotation(1002,new BigDecimal("65"), new BigDecimal("69")));
storeQuotation(new Quotation(1003,new BigDecimal("70"), new BigDecimal("71")));
storeQuotation(new Quotation(1004,new BigDecimal("71"), new BigDecimal("73")));
storeQuotation(new Quotation(1005,new BigDecimal("90"), new BigDecimal("95")));
storeQuotation(new Quotation(1006,new BigDecimal("92"), new BigDecimal("93")));
storeQuotation(new Quotation(1007,new BigDecimal("94"), new BigDecimal("98")));
storeQuotation(new Quotation(1008,new BigDecimal("90"), new BigDecimal("92")));
storeQuotation(new Quotation(1009,new BigDecimal("92"), new BigDecimal("95")));
out - Not Sorted
id - 1000. Bid - 99. Ask - 104. Spread = 5
id - 1001. Bid - 69. Ask - 72. Spread = 3
id - 1002. Bid - 65. Ask - 69. Spread = 4
id - 1003. Bid - 70. Ask - 71. Spread = 1
id - 1004. Bid - 71. Ask - 73. Spread = 2
id - 1005. Bid - 90. Ask - 95. Spread = 5
id - 1006. Bid - 92. Ask - 93. Spread = 1
id - 1007. Bid - 94. Ask - 98. Spread = 4
id - 1008. Bid - 90. Ask - 92. Spread = 2
id - 1009. Bid - 92. Ask - 95. Spread = 3
And I just need to sort this list by the difference between bidPrice and askPrice. I tried this method...
public static List<Quotation> getSpreadsList(boolean decreasing) {
List<Quotation> sortedBySpread = QuotationsStoreImpl.quotationList;
Collections.sort(sortedBySpread, (a, b) ->
(a.getBidPrice().intValue() - b.getAskPrice().intValue()));
// sortedBySpread.sort((a, b) ->
// (a.getBidPrice().intValue() - b.getAskPrice().intValue()));
if (decreasing) {
Collections.reverse(sortedBySpread);
}
return sortedBySpread;
}
}
But without success...
out - Sorted
id - 1002. Bid - 65. Ask - 69. Spread = 4
id - 1003. Bid - 70. Ask - 71. Spread = 1
id - 1004. Bid - 71. Ask - 73. Spread = 2
id - 1001. Bid - 69. Ask - 72. Spread = 3
id - 1008. Bid - 90. Ask - 92. Spread = 2
id - 1009. Bid - 92. Ask - 95. Spread = 3
id - 1006. Bid - 92. Ask - 93. Spread = 1
id - 1007. Bid - 94. Ask - 98. Spread = 4
id - 1005. Bid - 90. Ask - 95. Spread = 5
id - 1000. Bid - 99. Ask - 104. Spread = 5
The list is mixed but not sorted according to my criteria ! Spread not sorted !
How can I sort this list correct, by spread ?
I don't have much experience in java. And all my attempts have come to nothing.
CodePudding user response:
Collections.sort(sortedBySpread, (a, b) -> (a.getBidPrice().intValue() - b.getAskPrice().intValue()));
does some math that makes little since since it subtracts the ask from the bid of two different quotes.
Instead you should calculate the spread of a
and then subtract the spread of b
:
Collections.sort(sortedBySpread, (a, b) -> (a.getBidPrice().intValue() - a.getAskPrice().intValue()) - (b.getBidPrice().intValue() - b.getAskPrice().intValue()));
Generally this could be expanded into the following to make it more clear what is going on:
Collections.sort(sortedBySpread, (Quotation a, Quotation b) -> {
int spreadA = a.getBidPrice().intValue() - a.getAskPrice().intValue();
int spreadB = b.getBidPrice().intValue() - b.getAskPrice().intValue();
return spreadA - spreadB;
});
But starting with the first snippet IntelliJ suggest the arguably far cleaner solution
Collections.sort(sortedBySpread, Comparator.comparingInt(a -> (a.getBidPrice().intValue() - a.getAskPrice().intValue())));
And going from there it might make sense to have a getSpread
on Quotation
:
public int getSpread() {
return bidPrice.intValue() - askPrice.intValue();
}
which would then allow
Collections.sort(sortedBySpread, Comparator.comparingInt(Quotation::getSpread));
And finally
sortedBySpread.sort(Comparator.comparingInt(Quotation::getSpread));
without the need for Collections.sort
.
CodePudding user response:
For demo, I put your values in a list. I also added the following to your class.
public BigDecimal getSpread() {
return askPrice.subtract(bidPrice);
}
public String toString() {
return "id - %d bid - %6.2f ask - %6.2f spread - %6.2f".formatted(id, bidPrice, askPrice,getSpread());
}
The data
List<Quotation> quotes = new ArrayList<>(List.of(
(new Quotation(1000,new BigDecimal("99"), new BigDecimal("104"))),
(new Quotation(1001,new BigDecimal("69"), new BigDecimal("72"))),
(new Quotation(1002,new BigDecimal("65"), new BigDecimal("69"))),
(new Quotation(1003,new BigDecimal("70"), new BigDecimal("71"))),
(new Quotation(1004,new BigDecimal("71"), new BigDecimal("73"))),
(new Quotation(1005,new BigDecimal("90"), new BigDecimal("95"))),
(new Quotation(1006,new BigDecimal("92"), new BigDecimal("93"))),
(new Quotation(1007,new BigDecimal("94"), new BigDecimal("98"))),
(new Quotation(1008,new BigDecimal("90"), new BigDecimal("92"))),
(new Quotation(1009,new BigDecimal("92"), new BigDecimal("95")))));
The sorting part is simple. Just use a comparator, referencing the spread.
quotes.sort(Comparator.comparing(Quotation::getSpread));
And print
for(Quotation q : quotes) {
System.out.println(q);
}
Prints
id - 1003 bid - 70.00 ask - 71.00 spread - 1.00
id - 1006 bid - 92.00 ask - 93.00 spread - 1.00
id - 1004 bid - 71.00 ask - 73.00 spread - 2.00
id - 1008 bid - 90.00 ask - 92.00 spread - 2.00
id - 1001 bid - 69.00 ask - 72.00 spread - 3.00
id - 1009 bid - 92.00 ask - 95.00 spread - 3.00
id - 1002 bid - 65.00 ask - 69.00 spread - 4.00
id - 1007 bid - 94.00 ask - 98.00 spread - 4.00
id - 1000 bid - 99.00 ask - 104.00 spread - 5.00
id - 1005 bid - 90.00 ask - 95.00 spread - 5.00