根据Java中对象属性的最常见值过滤对象的Arraylist
Posted
技术标签:
【中文标题】根据Java中对象属性的最常见值过滤对象的Arraylist【英文标题】:Filter an Arraylist of object based on the most common value of an attribute of the object in Java 【发布时间】:2018-09-08 12:56:16 【问题描述】:我正在尝试根据对象变量的值过滤 Java 对象的 ArrayList。
如果这听起来令人困惑,我很抱歉。也许代码会更好地解释它。
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));
和对象
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;
如您所见,arraylist 中会有重复项。我只能在它成为数组列表后对其进行过滤,因为我正在读取文件然后将其放入 ArrayList。
我试图实现的输出如下所示
Uvumvew,10
Ossas,10
Dummy,7
因为 10、10、7 分别是 Uvumvew、Ossas 和 Dummy 最常见的值。我曾尝试使用 Collection 并过滤值,但由于对象之间包含重复值,因此这是不可能的。
我的尝试是这样的
Collection<Data> nonDuplicatedName = list.stream()
.<Map<String, Data>> collect(HashMap::new,(m,e)->m.put(e.getName(), e), Map::putAll)
.values();
它会产生这样的输出,这是错误的
Dummy 8.0
Uvumvew 14.0
Ossas 10.0
对我的理解的任何帮助或更正将不胜感激。谢谢!
【问题讨论】:
发布您尝试解决问题的代码 可能有一种方法可以使用流来执行此操作,或者您可以构建一个值映射到计数,然后检查哪种模式 在Data
类上实现hashCode()
和equals()
,然后使用Set<Data>
而不是ArrayList
。
我添加了我的尝试。如有错误请指正
@SeanBright 我也是,一开始也在考虑一个 Set,直到我看到他们想要保留一个特定元素(模式,而不是第一个)
【参考方案1】:
这可能有点过于复杂,并且使用中间映射会产生开销,但这应该可以解决您的问题:
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
我们先统计一下Data#value
在原文中的频率。所以我们只按Data#name
拳头分组,以获得相似对象的地图,然后我们按Data#value
分组,同时计算个人value
出现的次数。这将给我们一个Map
,其中keys
是Data#names
和values
频率Data#values
Uvumvew=10.0=3, 11.0=1, 14.0=2
现在有了这个映射,我们可以创建一个新的 Data
具有最频繁值的对象 - 只需迭代 tmpMap
并使用 Map#key
作为 Data#name
和来自嵌套频率映射的最大元素 10.0=3, 11.0=1, 14.0=2
作为 @ 构造新对象987654337@
tmpMap.entrySet()
.stream()
.map(
entry -> new Data(
entry.getKey(),
entry.getValue().entrySet().stream()
.max(Map.Entry.comparingByValue()).get().getKey()
)
).collect(toList());
//[Dataname='Dummy', value=7.0, Dataname='Ossas', value=10.0, Dataname='Uvumvew', value=10.0]
我希望这会有所帮助。
【讨论】:
非常感谢您的回答。我清楚地理解这个概念! :D 但是,counting() 和 toList() 方法返回错误。有什么我必须导入或更改 JDK 的吗?? @SmileyHuehue,不客气。是的,您需要导入 Collectors:import static java.util.stream.Collectors.*;
如果您觉得这个答案有用,请不要忘记接受这个答案以上是关于根据Java中对象属性的最常见值过滤对象的Arraylist的主要内容,如果未能解决你的问题,请参考以下文章