正确删除列表中的重复项

时间:2018-04-09 13:15:29

标签: java list duplicates

给定以下数据类型TestcaseXQueryTestpathFirstInputFileSecondInputFileExpected

如何正确删除重复项。

重复的定义:

如果FirstInputFile已在列表中SecondInputFile,则反之亦然。

这是Testdata

tcs.add(new HeaderAndBodyTestcase("XQ 1", "/1", "FAIL", "FAIL2", "FAILED"));
    tcs.add(new HeaderAndBodyTestcase("XQ 1", "/1", "FAIL2", "FAIL", "FAILED"));
    tcs.add(new HeaderAndBodyTestcase("XQ 2", "/2", "FAIL4", "FAIL3", "FAILED2"));
    tcs.add(new HeaderAndBodyTestcase("XQ 2", "/2", "FAIL3", "FAIL4", "FAILED2"));

这是函数

 protected void deleteExistingDuplicatesInArrayList(final ArrayList<HeaderAndBodyTestcase> list) {


    for (int idx = 0; idx < list.size() - 1; idx++) {

        if (list.get(idx).firstInputFile.equals(list.get(idx).secondInputFile)
                || (list.get(idx + 1).firstInputFile.equals(list.get(idx).firstInputFile)
                        && list.get(idx).secondInputFile.equals(list.get(idx + 1).secondInputFile)
                        || (list.get(idx).firstInputFile.equals(list.get(idx + 1).secondInputFile)
                                && list.get(idx).secondInputFile.equals(list.get(idx + 1).firstInputFile)))) {
            list.remove(idx);
        }

    }

}

这个解决方案已经有效,但看起来很糟糕,那么有更好的解决方案吗?

2 个答案:

答案 0 :(得分:2)

如果需要,

使用比较器将所有内容放入Set,如果您确实需要List(而不是Collection),则从该集创建一个列表

Set<HeaderAndBodyTestcase> set = new Hashset<>(list);

答案 1 :(得分:1)

鉴于你相当特殊的平等&#34;约束,我认为最好的方法是维护两组已经看过的第一和第二个输入文件和一个循环:

Set<String> first = new HashSet<>();
Set<String> second = new HashSet<>();
for (HeaderAndBodyTestcase tc : tcs) {
    if (! first.contains(tc.getSecondInputFile()) && 
            ! second.contains(tc.getFirstInputFile())) {
        first.add(tc.getFirstInputFile());
        second.add(tc.getSecondInputFile());
        System.out.println(tc); // or add to result list
    }
}

如果&#34;等于&#34;这也将有效。元素在原始列表中不会一个接一个地出现。

另请注意,在迭代相同列表时从列表中删除元素(有时工作)通常会产生意外结果。最好创建一个新的过滤列表,或者如果必须删除,请从该列表中创建Iterator并使用它remove方法。

仔细检查(是的,我花了很长时间才能理解你的代码),你当前工作代码中的条件实际上与我从你的问题中理解的条件大不相同,即:

  • 如果第一个和第二个相同(实际上从未检查过列表中的最后一个元素),则删除元素
  • 如果第一个与最后一个相同,则删除元素,第二个与最后一个相同
  • 如果第一个与上一秒相同,则删除反之亦然
  • 仅考虑连续元素(来自评论)

考虑到这些限制,这些集合是不需要的,并且考虑到两者元素必须匹配(无论是&#39;直接&#39;还是&#39;交叉&# 39)。相反,您可以按原样使用相当多的代码,但我仍然会使用Iterator并跟踪last元素,并分割不同的检查以使整个代码更容易理解

HeaderAndBodyTestcase last = null;
for (Iterator<HeaderAndBodyTestcase> iter = list.iterator(); iter.hasNext();) {
    HeaderAndBodyTestcase curr = iter.next();
    if (curr.firstInputFile.equals(curr.secondInputFile)) {
        iter.remove();
    }
    if (last != null) {
        boolean bothEqual = curr.firstInputFile.equals(last.firstInputFile) 
                         && curr.secondInputFile.equals(last.secondInputFile);
        boolean crossedEqual = curr.secondInputFile.equals(last.firstInputFile)
                            && curr.firstInputFile.equals(last.secondInputFile);
        if (bothEqual || crossedEqual) {
            iter.remove();
        }
    }
    last = curr;
}