Java - removing objects in a collection that are in another collection with an arbitrary "equals" value
It's very easy if I just want to base it on absolute equality. I would just do:
collectionA.removeAll(collectionB).
However, let's say I have this object:
class Item {
private String color;
private String name;
private String type;
}
And two collections ...
List<Item> items1, List<item> items2.
... but I just want to remove everything from item1 with the same name and print as something in item2.
Please note that I cannot subclass or define equals, hashcode for this class.
I would like it to be the same complexity of the existing collection.removeAll method.
The best solution I can think of would be something like this:
class SimpleItem {
String name;
String type;
Item item;
public SimpleItem(Item item) {
this.name = item.getName();
this.type = item.getType();
}
@Override
public boolean equals(Object obj) {
...
}
@Override
public int hashCode() {
...
}
}
Set<SimpleItem> simpleItems1 = ...;
for (Item item : items1) {
simpleItems1.add(new SimpleItem(item));
}
Set<SimpleItem> simpleItems2 = ...;
for (Item item : items2) {
simpleItems2.add(new SimpleItem(item));
}
simpleItems1.removeAll(simpleItems2);
Set<Item> items = ...;
for (SimpleItem simpleItem : simpleItems) {
items.add(simpleItem.item);
}
... but it's insanely wordy. It's Java 8. What clever solution am I missing?
source to share
You mentioned that this is Java 8. In this case, you have a very simple and straightforward way to achieve this:
list1.removeIf(item1 -> list2.stream().anyMatch(item2 -> customEquals(item1, item2));
If your method customEquals
is a member Item
, you can use a method reference to make it a little neat:
list1.removeIf(item -> list2.stream().anyMatch(item::customEquals));
In your case, you can put your condition directly into the statement, rather than creating a separate method:
list1.removeIf(item1 -> list2.stream().anyMatch(item2 ->
item1.getName().equals(item2.getName()) && item1.getType().equals(item2.getType())));
Conveniently removeIf
is the default member of an interface Collection
, so any class that implements Collection
must support it if the implementation iterator does remove
.
source to share