3

This is very easy if I just want to base this on absolute equality. I'd 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 that has the same name and type as something in item2.

Note that I can't subclass or define equals, hashcode for this class.

I'd want this to be the same complexity of the existing collections.removeAll method.

The best solution I can think of would be something like:

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 that is insanely verbose. It's Java 8. What clever solution am I missing?

Jeremy
  • 5,365
  • 14
  • 51
  • 80
  • it is not clear what you are trying to do, but if you want to filter some elements from `Collection` you could do something like `persons.parallelStream().filter((Person p)-> {return p.getAge() > 18;});` – jmj May 21 '15 at 23:41
  • @keyser If my implementation seems right, I guess I'll stick with it. It just seems like so much text for a pretty simple operation. – Jeremy May 21 '15 at 23:42
  • @Jeremy I kinda missed the part about needing to wrap it. Hopefully you can do something like what Joshi suggested instead. – keyser May 21 '15 at 23:44

2 Answers2

3

You mention that it's Java 8. In that case you have a very simple and straightforward way to achieve this:

list1.removeIf(item1 -> list2.stream().anyMatch(item2 -> customEquals(item1, item2));

If your customEquals method is a member of Item you could use a method reference to make it a bit neater:

list1.removeIf(item -> list2.stream().anyMatch(item::customEquals));

In your case you could 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 a default member of the Collection interface so any class that implements Collection should support it as long as the implementation's iterator supports remove.

sprinter
  • 27,148
  • 6
  • 47
  • 78
0

You can use apache commons class to do so. Good examples are here

Another link

Community
  • 1
  • 1
bobs_007
  • 178
  • 1
  • 10