根据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&lt;Data&gt; 而不是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,其中keysData#namesvalues 频率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的主要内容,如果未能解决你的问题,请参考以下文章

根据属性值用 lodash 过滤对象数组

根据来自不同对象数组的属性和值过滤对象数组

JavaScript 根据属性值过滤对象数组

使用 Django 根据用户选择的另一个对象属性的值来过滤属性的对象值

使用嵌套对象迭代 json 并根据属性值进行过滤

NSPredicate 根据嵌套结构中的属性过滤自定义对象