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?

+3


source to share


2 answers


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

.

+3


source


You can use the apache class for this. Good examples here



Another link

0


source







All Articles