从基于两个字段的自定义对象列表中删除重复项

问题描述

我有两个自定义对象列表都是 List<LogEntry>。其中一个属性typeOfExceptiondatestackTrace,另一个只包含typeOfExceptionstackTrace。我想要做的是根据他们的 typeOfExceptionstackTrace 删除重复的日志条目。我定义唯一堆栈跟踪的方式是,如果第一个“at line”相同,即

[25/05/21 10:28:41:481 BST] - IllegalStateException some text here
at com.google MyClass(Line 50)
[28/05/21 10:28:41:481 BST] - IllegalStateException some more text here
at com.google MyClass(Line 50)

被视为重复但

[25/05/21 10:28:41:481 BST] - IllegalStateException some text here
at com.google MyClass(Line 50)
[28/05/21 10:28:41:481 BST] - IllegalStateException some more text here
at com.google MyClass(Line 50000)

将被视为独一无二的。

我有一个名为 List<LogEntry>logEntries,其中包含 date,typeOfExceptionstackTrace我有一个名为 List<LogEntry>logEntriestocheckForDupes,它是一个 LogEntry 对象,但这次只包含 typeOfExceptionstackTrace 行的顶部(注意所有属性是字符串)。

我到目前为止的代码

HashSet<Object> uniqueStackTraces =new HashSet<>();
    logEntryObjectstocheckForDupes.removeIf(c -> !uniqueStackTraces.add(Arrays.asList(c.getTypeOfexception(),c.getStackTrace())));

我认为这是有效的(当我从 887 个异常减少到只有 14 个时,我并不完全相信)。是否有一些方法/逻辑可以找到每个唯一条目的索引。那样的话,我可以只存储一个唯一索引列表并从每个具有唯一索引的对象的 List<LogEntry> 创建一个 logEntries,而不是创建一个新的 HashSet?

我很困惑,不确定我的代码是否真的按预期工作,因此非常感谢任何建议/输入。问题类似于 (Removing duplicates from the list of objects based on more than one property in java 8) 并且我使用了这里的一些逻辑。

解决方法

分组和聚合:

public static void main(String[] args) {

    List<LogEntry> list1 = IntStream.range(0,100).mapToObj(i -> random(true)).collect(toList());
    List<LogEntry> list2 = IntStream.range(0,100).mapToObj(i -> random(false)).collect(toList());

    // join removing dups,get the last date
    Collection<LogEntry> result = Stream.concat(list1.stream(),list2.stream())
            .collect(toMap(
                    // the key (better use a Tuple<> type instead concatenate strings)
                    x -> x.typeOfException + ":" + x.stackTrace,x -> x,// the max non null date
                    (a,b) -> a.date == null ? b : b.date == null ? a : a.date < b.date ? b : a))
            .values();

    result.forEach(e -> System.out.printf("%s,%s,%d%n",e.typeOfException,e.stackTrace,e.date));
}

@AllArgsConstructor
static class LogEntry {
    public String typeOfException;
    public String stackTrace;
    public Integer date;

    public static LogEntry random(boolean withDates) {
        ThreadLocalRandom rnd = ThreadLocalRandom.current();
        return new LogEntry("E" + rnd.nextInt(3),"S" + rnd.nextInt(3),withDates ? rnd.nextInt() : null);
    }
}

带输出

E2,S1,1974693605
E1,S0,2085047733
E2,1766963016
E0,S2,2106321704
E0,1752799219
E1,2123681998
E1,1522756354
E0,1578552430
E2,1969494110

如果我们有几个日期为空的出现

List<LogEntry> list1 = IntStream.range(0,4).mapToObj(i -> random(true)).collect(toList());
List<LogEntry> list2 = IntStream.range(0,100).mapToObj(i -> random(false)).collect(toList());

带输出

E2,null
E1,null
E2,null
E0,2123867824
E1,13858484
E2,1347419477
E0,-135848900