有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java基于列表中的几个对象属性删除重复项

我有一个列表集合,其中每个度量包含多个属性,例如:metricName、命名空间、震源组、类型、组件、firstSeenTime、lastSeenTime等。此列表中有重复项,因此除firstSeenTime和lastSeenTime外,所有属性都相同。我正在寻找一种优雅的方法来过滤这个列表,并且只有在存在这样的重复项时才返回具有最新lastSeenTime的度量

比这更好的东西:

private List<Metric> processResults(List<Metric metrics) {
    List<Metric> results = new ArrayList<>();

    for (Metric incomingMetric: metrics) {

        // We need to implement "contains" below so that only properties
        // other than the two dates are checked.
        if (results.contains(incomingMetric) { 
            int index = results.indexOf(incomingMetric);
            Metric existing = results.get(index); 
            if (incomingMetric.getLastSeen().after(existing.getLastSeen())) {
                results.set(index, metricName);
            } else {
                // do nothing, metric in results is already the latest 
            }
        } else {
            // add incomingMetric to results for the first time
            results.add(incomingMetric);
        }
    }

    return results;
}

结果。包含检查是通过迭代结果中的所有度量并检查每个对象是否匹配除两个日期之外的属性来完成的

有什么更好的方法可以兼顾优雅和性能


共 (3) 个答案

  1. # 1 楼答案

    在java中,比较事物最优雅的方式是Comparator接口。您应该使用以下方法删除重复项:

    public List<Metric> removeDuplicates(List<Metric> metrics) {
    
        List<Metric> copy = new ArrayList<>(metrics);
        //first sort the metrics list from most recent to older
        Collections.sort(copy, new SortComparator());
    
        Set<Metric> set = new TreeSet<Metric>(new Comparator<Metric>() {
    
            @Override
            public int compare(Metric o1, Metric o2) {
                int result = 0;
                // compare the two metrics given your rules
                return result;
            }
        });
    
        for(Metric metric : copy) {
            set.add(metric);
        }
    
        List<Metric> result = Arrays.asList(set.toArray());
        return result;
     }
    
    class SortComparator implements Comparator<Metric> {
    
        @Override
        public int compare(Metric o1, Metric o2) {
            int result = 0;
            if(o2.getLastSeenTime() != null && o1.getLastSeenTime() != null) {
                result = o2.getLastSeenTime().compareTo(o1.getLastSeenTime());
            }
            return result;
        }
    
    }
    

    这种方法的优点在于,您可以编写一系列比较器,并提供Factory在运行时选择最佳方法来比较度量,并在运行时条件中删除或不删除重复的实例:

    public void removeDuplicates(List<Metric> metrics, Comparator<Metric> comparator) {
    
        List<Metric> copy = new ArrayList<>(metrics);
        Collections.sort(copy, new SortComparator());
    
        Set<Metric> set = new TreeSet<Metric>(comparator);
        for(Metric metric : copy) {
            set.add(metric);
        }
        List<Object> result = Arrays.asList(set.toArray());
        return result;
     }
    
  2. # 2 楼答案

    谢谢你的回答。我使用map方法,因为它不需要额外的排序和拷贝

    @VisibleForTesting
    Set<Metric> removeDuplicates(List<Metric> metrics) {
    
    Map<RawMetric, Metric> metricsMap = new HashMap<>();
    for (Metric metric : metrics) {
        RawMetric rawMetric = RawMetric.builder()
                .metricName(metric.getName())
                .metricType(metricName.getMetricType())
                ... // and more
                .build();
    
            // pick the latest updated metric (based on lastSeen date)
            BiFunction<RawMetric, Metric, Metric> biFunction =
                (k, v) -> Metric.builder()
                        .name(k.getMetricName())
                        .metricType(k.getMetricType())
                        ... // and more                        
                        .lastSeen(v.getLastSeen().after(
                            metricName.getLastSeen()) ? v.getLastSeen() : 
                                metricName.getLastSeen())
                        .firstSeen(v.getFirstSeen())
                        .build();
    
            metricsMap.putIfAbsent(rawMetric, metric);
            metricsMap.computeIfPresent(rawMetric, biFunction);
        }
    
        return ImmutableSet.copyOf(metricsMap.values());
    }
    
    @Value
    @Builder
    static class RawMetricName {
        private String metricName;
        private String metricType;
        private String ad;
        private String project;
        private String fleet;
        private String host;
        private int granularity;
    }
    
  3. # 3 楼答案

    我不确定您是如何生成List<Metric>。但是如果您可以维护一个Map<String, Metric>而不是该列表,您可以尝试以下方法

    因此,这张地图的关键将是你需要比较的所有这些值的组合。(日期属性除外。)

    Key: “{metricName}${type}$.....”

    为此,可以使用getter在Metric对象中维护另一个属性。当您调用getter时,它将返回密钥

    然后在放入地图之前检查密钥是否存在。如果存在,则获取该键在映射中存储的度量,并进行日期比较以查找最新的度量对象。如果是最新的,请使用新对象替换地图存储的对象

    PS:对这两种情况进行执行时间比较。所以你会找到最好的方法