我有一个哈希表,其键值为Map<String,List<Trade>>
。在值对象中,即List<Trade>
,我必须比较每个对象。如果对象的任何两个属性名称“ TradeType”相同,则必须从列表中删除这两个属性。我正在努力实现以下目标。但是我得到了“数组索引超出限制的异常”,还有没有更好的方法来使用流比较列表中的同一对象?
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);
}
}
}
});
答案 0 :(得分:2)
您的描述与您的代码并不完全同步,因此我将提供一些解决方案,您可以选择其中的一种。
首先IndexOutOfBoundsException
可以通过将循环条件从i <= tl.size()
更改为i < tl.size()
来解决。这是因为列表基于tl.size() - 1
,因此列表中的最后一项位于索引0
。
要改善您当前的尝试,您可以按照以下步骤进行操作:
tradeMap.values()
.stream()
.filter(list -> list.size() > 1)
.forEach(T::accept);
其中accept
定义为:
private static void accept(List<Trade> list) {
String et = list.get(0).getTradeType();
list.subList(1, list.size()).removeIf(e -> e.getTradeType().equals(et));
}
和T
应该替换为包含accept
方法的类。
上面的代码段仅按交易类型删除第一个元素之后的对象,该对象等于第一个元素,这就是您的示例代码段所尝试的操作。但是,如果您要区分所有对象,则一种选择是如下重写equals
类中的hashcode
和Trade
:
@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);
}
然后accept
方法需要修改为:
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
}
或者如果您根本不想覆盖均值和哈希码,则可以使用toMap
收集器来获取不同的对象:
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
}
但是,如果您说:
“如果对象的属性名称“ TradeType”中的任何两个相同,则我 必须从列表中删除这两个。”
您实际上想通过Trade
删除所有相等的tradeType
对象,这些对象具有2次或多次出现,然后将accept
方法修改如下:
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())));
}
答案 1 :(得分:1)
Map<String,List<Trade>> tradeMap = new HashMap<>();
tradeMap.put("1",Arrays.asList(new Trade("A"),new Trade("B"),new Trade("A")));
tradeMap.put("2",Arrays.asList(new Trade("C"),new Trade("C"),new Trade("D")));
Map<String,Collection<Trade>> tradeMapNew = tradeMap.entrySet()
.stream()
.collect(Collectors.toMap(Entry::getKey,
e -> e.getValue().stream() //This is to remove the duplicates from the list.
.collect(Collectors.toMap(Trade::getTradeType,
t->t,
(t1,t2) -> t1,
LinkedHashMap::new))
.values()));
输出:
{1=[A, B], 2=[C, D]}
答案 2 :(得分:1)
public void test(){
Map<String, List<Trade>> data = new HashMap<>();
List<Trade> list1 = Arrays.asList(new Trade("1"), new Trade("2"), new Trade("1"), new Trade("3"), new Trade("3"), new Trade("4"));
List<Trade> list2 = Arrays.asList(new Trade("1"), new Trade("2"), new Trade("2"), new Trade("3"), new Trade("3"), new Trade("4"));
data.put("a", list1);
data.put("b", list2);
Map<String, List<Trade>> resultMap = data.entrySet()
.stream()
.collect(Collectors.toMap(Entry::getKey, this::filterDuplicateListObjects));
resultMap.forEach((key, value) -> System.out.println(key + ": " + value));
// Don't forget to override the toString() method of Trade class.
}
public List<Trade> filterDuplicateListObjects(Entry<String, List<Trade>> entry){
return entry.getValue()
.stream()
.filter(trade -> isDuplicate(trade, entry.getValue()))
.collect(Collectors.toList());
}
public boolean isDuplicate(Trade trade, List<Trade> tradeList){
return tradeList.stream()
.filter(t -> !t.equals(trade))
.noneMatch(t -> t.getTradeType().equals(trade.getTradeType()));
}
答案 3 :(得分:0)
Map<String, List<Trade>> tradeMap = new HashMap<>();
tradeMap.values()
.stream()
.forEach(trades -> trades.stream()
.collect(Collectors.groupingBy(Trade::getType))
.values()
.stream()
.filter(tradesByType -> tradesByType.size() > 1)
.flatMap(Collection::stream)
.forEach(trades::remove));