SmileyHuehue
SmileyHuehue

Reputation: 43

Filter an Arraylist of object based on the most common value of an attribute of the object in Java

I am trying to filter an ArrayList of a Java Object based on the value of the variable of the object.

I'm sorry if it sounds confusing. Maybe the code will explain it better.

public static void main(String[] args)
{
    ArrayList<Data> list = new ArrayList<>();

    list.add(new Data("Uvumvew", 10));
    list.add(new Data("Uvumvew", 10));
    list.add(new Data("Uvumvew", 10));
    list.add(new Data("Uvumvew", 11));
    list.add(new Data("Uvumvew", 14));
    list.add(new Data("Uvumvew", 14));
    list.add(new Data("Ossas", 5));
    list.add(new Data("Ossas", 5));
    list.add(new Data("Ossas", 10));
    list.add(new Data("Ossas", 10));
    list.add(new Data("Ossas", 10));
    list.add(new Data("Dummy", 7));
    list.add(new Data("Dummy", 7));
    list.add(new Data("Dummy", 7));
    list.add(new Data("Dummy", 8));
    list.add(new Data("Dummy", 8));
}

and the Object

private String name;
private double value;

public Data() {
}

public Data(String name, double value) {
    super();
    this.name = name;
    this.value = value;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public double getValue() {
    return value;
}

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

There will be duplicates in the arraylist as you can see. I can only filter it after it being an arraylist since I'm reading files then putting it into the ArrayList.

The output I'm trying to achieve look like this

Uvumvew,10
Ossas,10
Dummy,7

Since 10,10,7 are the most common value for Uvumvew,Ossas,and Dummy respectively. I have tried using Collection and to filter the value but as there contains duplicate values among the Object, it is not possible.

My attempt is like this

Collection<Data> nonDuplicatedName = list.stream()
               .<Map<String, Data>> collect(HashMap::new,(m,e)->m.put(e.getName(), e), Map::putAll)
               .values();

it produce a output like this which is wrong

Dummy 8.0
Uvumvew 14.0
Ossas 10.0

Any help or correction to my understanding would be appreciated. Thanks !

Upvotes: 4

Views: 580

Answers (1)

Anton Balaniuc
Anton Balaniuc

Reputation: 11739

This might be a bit over-complicated and there is an overhead of using intermediate map, but this should solve your problem:

Map<String, Map<Double,Long>> tmpMap = list.stream()
        .collect(
                groupingBy(Data::getName,
                        groupingBy(Data::getValue,counting())
                ));
// {Dummy={8.0=2, 7.0=3}, Ossas={10.0=3, 5.0=2}, Uvumvew={10.0=3, 11.0=1, 14.0=2}}

Let's count frequency of Data#value in the original first. So we just group by Data#name fist, to get a map of similar objects and after this we group by Data#value and counting at the same time how many times individual value is present. This will give us a Map where keys are Data#names and values frequency of Data#values Uvumvew={10.0=3, 11.0=1, 14.0=2} Now having this map we can create a new Data objects with most frequent value - by just to iterating over tmpMap and constructing new objects using Map#key as Data#name and maximum element from nested frequency map {10.0=3, 11.0=1, 14.0=2} as Data#value

tmpMap.entrySet()
        .stream()
        .map(
                entry -> new Data(
                        entry.getKey(),
                        entry.getValue().entrySet().stream()
                                .max(Map.Entry.comparingByValue()).get().getKey()
                )
        ).collect(toList()); 
//[Data{name='Dummy', value=7.0}, Data{name='Ossas', value=10.0}, Data{name='Uvumvew', value=10.0}]

I hope this helps.

Upvotes: 3

Related Questions