I have a hashmap with key,value as Map<String,List<Trade>>. In the value object i.e. List<Trade> I have to compare each object. If any two of the object's property name "TradeType" is same then I have to remove those two from the list. I am trying to achieve as below. But I am getting "Array index out of bound exception" Also is there any better way to compare the same object inside list using streams??
Map<String,List<Trade>> tradeMap = new HashMap<>();
// Insert some data here
tradeMap.entrySet()
.stream()
.forEach(tradeList -> {
List<Trade> tl = tradeList.getValue();
String et = "";
// Is there a better way to refactor this?
for(int i = 0;i <= tl.size();i++){
if(i == 0) {
et = tl.get(0).getTradeType();
}
else {
if(et.equals(tl.get(i).getTradeType())){
tl.remove(i);
}
}
}
});
Your description is not completely in sync with what your code does so I will provide a couple of solutions in which you can choose the one you're after.
First and foremost as for the IndexOutOfBoundsException you can solve it by changing the loop condition from i <= tl.size() to i < tl.size(). This is because the last item in a list is at index tl.size() - 1 as lists are 0 based.
To improve upon your current attempt you can do it as follows:
tradeMap.values()
.stream()
.filter(list -> list.size() > 1)
.forEach(T::accept);
where accept is defined as:
private static void accept(List<Trade> list) {
String et = list.get(0).getTradeType();
list.subList(1, list.size()).removeIf(e -> e.getTradeType().equals(et));
}
and T should be substituted with the class containing the accept method.
The above code snippet only removes objects after the first element that are equal to the first element by trade type, which is what your example snippet is attempting to do. if however, you want distinct of all objects then one option would be to override equals and hashcode in the Trade class as follows:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Trade trade = (Trade) o;
return Objects.equals(tradeType, trade.tradeType);
}
@Override
public int hashCode() {
return Objects.hash(tradeType);
}
Then the accept method needs to be modified to become:
private static void accept(List<Trade> list) {
List<Trade> distinct = list.stream()
.distinct()
.collect(Collectors.toList());
list.clear(); // clear list
list.addAll(distinct); // repopulate with distinct objects by tradeType
}
or if you don't want to override equals and hashcode at all then you can use the toMap collector to get the distinct objects:
private static void accept(List<Trade> list) {
Collection<Trade> distinct = list.stream()
.collect(Collectors.toMap(Trade::getTradeType,
Function.identity(), (l, r) -> l, LinkedHashMap::new))
.values();
list.clear(); // clear list
list.addAll(distinct); // repopulate with distinct objects by tradeType
}
if however, when you say:
"If any two of the object's property name "TradeType" is same then I have to remove those two from the list."
you actually want to remove all equal Trade objects by tradeType that have 2 or more occurrences then modify the accept method to be as follows:
private static void accept(List<Trade> list) {
list.stream()
.collect(Collectors.groupingBy(Trade::getTradeType))
.values()
.stream()
.filter(l -> l.size() > 1)
.map(l -> l.get(0))
.forEach(t -> list.removeIf(trade -> trade.getTradeType().equals(t.getTradeType())));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With