Remove element with duplicate property based on another property from list using java 8

Ellone :

I'm struggling to reduce a list :

Let's say I have a List<Item> listItems with an Item class defined such as :

public class Item {
    private String effect;
    private String value;

    public String getEffect() {
        return effect;
    }

    public void setEffect(String effect) {
        this.effect = effect;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

Now, in my listItems list, I have some elements with the same effect property.

I want to remove all element from my listItems list with the same effect property except the one with the higher value property. (value is number represented as a String).

Also, I wanna keep all the element with an unique effect property.

How can I achieve that ? I guess I'm gonna have to deal with Comparator.

Federico Peralta Schaffner :

It seems that you want to group the items of your list by effect, using max(value) as an aggregation. You can do this as follows:

Map<String, Item> byEffectHavingMaxValue = listItems.stream()
    .collect(Collectors.toMap(
            Item::getEffect,      // group by effect
            Function.identity(),  // keep items as values
            BinaryOperator.maxBy( // when effect exists, keep the item with max value
                    Comparator.comparingInt(i -> Integer.parseInt(i.getValue())))));

Collection<Item> result = byEffectHavingMaxValue.values();

The solution above collects elements of the stream to a Map. For this, it uses an overload of Collectors.toMap that requires 3 arguments:

  • keyMapper: a Function that transforms elements of the stream to keys
  • valueMapper: a Function that transforms elements of the stream to values
  • mergeFunction: a BinaryOperator that is used to resolve collisions between values associated with the same key

In this case, the Item::getEffect method reference is being used as the keyMapper function, which transforms an Item instance to its effect. Then, Function.identity() is being used as the valueMapper function, which does nothing, i.e. it leaves each Item instance untouched. Finally, BinaryOperator.maxBy(Comparator.comparingInt(i -> Integer.parseInt(i.getValue()))) is being used as the mergeFunction, which is a BinaryOperator that receives two values of the map that have the same key (i.e. two Item instances with the same effect), and resolves the collision in the map by selecting the Item instance that has the max value (value is first converted to Integer, so that we compare numeric values instead of strings).

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=114887&siteId=1