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

时间:2021-06-08 08:52:28

标签: java stack-trace logfile

我有两个自定义对象列表都是 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) 并且我使用了这里的一些逻辑。

1 个答案:

答案 0 :(得分:0)

分组和聚合:

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, S0, 1766963016
E0, S2, 2106321704
E0, S1, 1752799219
E1, S2, 2123681998
E1, S1, 1522756354
E0, S0, 1578552430
E2, S2, 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, S1, null
E1, S0, null
E2, S0, null
E0, S2, 2123867824
E1, S2, null
E0, S1, 13858484
E2, S2, null
E1, S1, 1347419477
E0, S0, -135848900
相关问题