Reputation: 43
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
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