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

3
我有两个自定义对象列表,它们都是 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)

这将被视为唯一的。

我有一个名为logEntriesList<LogEntry>,其中包含datetypeOfExceptionstackTrace。我还有另一个名为logEntriesToCheckForDupesList<LogEntry>,它是一个LogEntry对象,但这次只包含typeOfExceptionstackTrace中顶部的行(注意所有属性都是字符串)。

到目前为止,我写出的代码如下:

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

我认为下面的代码可以工作(虽然我还不完全相信,因为异常从887个减少到了14个)。有没有一种方法/逻辑来查找每个唯一条目的索引。那样的话,我就不需要创建一个新的HashSet了,而是可以只存储唯一索引的列表,并从logEntries中创建一个List<LogEntry>的对象,其中每个对象都具有唯一的索引?

我感到很困惑,不确定我的代码是否按照预期工作,所以非常感谢任何建议/输入。这个问题类似于 (在Java 8中基于多个属性从对象列表中删除重复项),并且我从中使用了一些逻辑。


你写过任何测试用例吗?也许你的代码是正确的。尝试循环遍历列表,打印出对象,并手动使用文本编辑器删除重复项,然后查看你的答案。通过快速查看链接问题中的答案,它们对我来说似乎是正确的。 - Gavin
我还没有编写任何测试用例,我花了一段时间在记事本中查看实际的日志文件,它似乎并不太不切实际。我认为从将近900个条目的初始列表大小变为14只是一个震惊!现在主要的问题是我需要找到这些唯一日志条目的索引,以便我可以获得完整的日志条目对象,包括日期/异常和堆栈跟踪。或者通过其他途径获取这些信息。 - Connor Gill
1个回答

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

这可能是一个愚蠢的问题,所以请原谅,列表1和列表2将成为我的两个列表,对吗?您只是用它们作为示例来显示输出? - Connor Gill
是的 @ConnorGill,根据你提供的两个列表,你期望的结果在 result = ... 中。 - josejuan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接