交叉比较 ArrayList 元素并删除重复项

发布于 2024-12-27 07:41:38 字数 834 浏览 2 评论 0原文

我有一个 ArrayList,它可能(也可能不)包含我需要从列表中删除的 MyObject 的重复项。我怎样才能做到这一点,我不必像在两个 for 循环中迭代列表并交叉检查每个项目与其他项目那样检查重复两次。

我只需要检查每个项目一次,因此比较 A:B 就足够了 - 我不想再次比较 B:A,因为我已经这样做了。

此外;我可以循环时从列表中删除重复项吗?或者这会以某种方式破坏列表和我的循环吗?

编辑:好吧,我忘记了浏览第一个答案的一个重要部分:MyObjectduplicate 不仅仅意味着 Java 方式的含义 Object.equals(Object ),但我需要能够使用我自己的算法比较对象,因为 MyObject 的相等性是使用一种算法计算的,该算法以我需要的特殊方式检查对象的字段来实施!

此外,我不能只覆盖 MyObject 中的 euqals,因为有几种不同的算法可以实现不同的策略来检查两个 MyObject 的相等性s - 例如,有一个简单的 HashComparer 和一个更复杂的 EuclidDistanceComparer,两者都是为 公共抽象实现不同算法的 AbstractComparers boolean isEqual(MyObject obj1, MyObject obj2);

I have an ArrayList<MyObject> that may (or may not) contain duplicates of MyObject I need to remove from the List. How can I do this in a way that I don't have to check duplication twice as I would do if I were to iterate the list in two for-loops and cross checking every item with every other item.

I just need to check every item once, so comparing A:B is enough - I don't want to compare B:A again, as I already did that.

Furthermore; can I just remove duplicates from the list while looping? Or will that somehow break the list and my loop?

Edit: Okay, I forgot an important part looking through the first answers: A duplicate of MyObject is not just meant in the Java way meaning Object.equals(Object), but I need to be able to compare objects using my own algorithm, as the equality of MyObjects is calculated using an algorithm that checks the Object's fields in a special way that I need to implement!

Furthermore, I can't just override euqals in MyObject as there are several, different Algorithms that implement different strategies for checking the equality of two MyObjects - e.g. there is a simple HashComparer and a more complex EuclidDistanceComparer, both being AbstractComparers implementing different algorithms for the public abstract boolean isEqual(MyObject obj1, MyObject obj2);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

负佳期 2025-01-03 07:41:38

对列表进行排序,重复项将彼此相邻,从而易于识别和删除。只需浏览列表并记住前一项的值,以便您可以将其与当前项进行比较。如果它们相同,则删除当前项目。

如果您使用普通的 for 循环来遍历列表,则可以控制当前位置。这意味着当您删除一个项目时,您可以递减位置 (n--),以便下一次循环将访问相同的位置(现在将是下一个项目)。

您需要提供自定义比较吗?这并不难:

Collections.sort(myArrayList, new Comparator<MyObject>() {

    public int compare(MyObject o1, MyObject o2) {
        return o1.getThing().compareTo(o2.getThing());
    }
});

我编写了这个示例,以便 getThing().compareTo() 代表您想要执行的任何操作来比较两个对象。如果它们相同,则必须返回一个整数;如果 o1 大于 o2,则必须返回大于 1 的整数;如果 o1 小于 o2,则必须返回 -1。如果 getThing() 返回一个 StringDate,那么您就已经准备好了,因为这些类有一个 compareTo > 已经有方法了。但您可以将所需的任何代码放入自定义Comparator 中。

Sort the list, and the duplicates will be adjacent to each other, making them easy to identify and remove. Just go through the list remembering the value of the previous item so you can compare it with the current one. If they are the same, remove the current item.

And if you use an ordinary for-loop to go through the list, you control the current position. That means that when you remove an item, you can decrement the position (n--) so that the next time around the loop will visit the same position (which will now be the next item).

You need to provide a custom comparison in your sort? That's not so hard:

Collections.sort(myArrayList, new Comparator<MyObject>() {

    public int compare(MyObject o1, MyObject o2) {
        return o1.getThing().compareTo(o2.getThing());
    }
});

I've written this example so that getThing().compareTo() stands in for whatever you want to do to compare the two objects. You must return an integer that is zero if they are the same, greater than 1 if o1 is greater than o2 and -1 if o1 is less than o2. If getThing() returned a String or a Date, you'd be all set because those classes have a compareTo method already. But you can put whatever code you need to in your custom Comparator.

暮倦 2025-01-03 07:41:38

创建一个集合,如果顺序不重要,它会自动为您删除重复项。

Set<MyObject> mySet = new HashSet<MyObject>(yourList);

Create a set and it will remove the duplicates automatically for you if the ordering is not important.

Set<MyObject> mySet = new HashSet<MyObject>(yourList);
悲喜皆因你 2025-01-03 07:41:38

实例化一个新的基于集合的集合 HashSet。不要忘记为 MyObject 实现 equals 和 hashcode。

祝你好运!

Instantiate a new set-based collection HashSet. Don't forget to implement equals and hashcode for MyObject.

Good Luck!

爱要勇敢去追 2025-01-03 07:41:38

如果对象顺序不重要

如果顺序不重要,您可以将列表的元素放入 Set 中:

Set<MyObject> mySet = new HashSet<MyObject>(yourList);

重复项将被自动删除。

如果对象顺序很重要

如果顺序很重要,那么您可以手动检查重复项,例如使用以下代码片段:

// Copy the list.
ArrayList<String> newList = (ArrayList<String>) list.clone();

// Iterate
for (int i = 0; i < list.size(); i++) {
    for (int j = list.size() - 1; j >= i; j--) {
        // If i is j, then it's the same object and don't need to be compared.
        if (i == j) {
            continue;
        }
        // If the compared objects are equal, remove them from the copy and break
        // to the next loop
        if (list.get(i).equals(list.get(j))) {
            newList.remove(list.get(i));
            break;
        }
        System.out.println("" + i + "," + j + ": " + list.get(i) + "-" + list.get(j));
    }
}

这将删除所有重复项,将最后一个重复值保留为原始条目。此外,它只会检查每个组合一次。

使用 Java 8

Java Streams 使其更加优雅:

List<Integer> newList = oldList.stream()
    .distinct()
    .collect(Collectors.toList());

如果您需要根据自己的定义考虑两个对象相等,您可以执行以下操作:(

public static <T, U> Predicate<T> distinctByProperty(Function<? super T, ?> propertyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(propertyExtractor.apply(t));
}

通过 Stuart Marks

然后你可以这样做:

List<MyObject> newList = oldList.stream()
    .filter(distinctByProperty(t -> {
        // Your custom property to use when determining whether two objects
        // are equal. For example, consider two object equal if their name
        // starts with the same character.
        return t.getName().charAt(0);
    }))
    .collect(Collectors.toList());

此外

,当迭代器(通常用于for-each 循环)正在循环数组。这将抛出一个ConcurrentModificationException。如果使用 for 循环来循环数组,则可以修改该数组。然后,您必须控制迭代器位置(在删除条目时递减它)。

If object order is insignificant

If the order is not important, you can put the elements of the list into a Set:

Set<MyObject> mySet = new HashSet<MyObject>(yourList);

The duplicates will be removed automatically.

If object order is significant

If ordering is significant, then you can manually check for duplicates, e.g. using this snippet:

// Copy the list.
ArrayList<String> newList = (ArrayList<String>) list.clone();

// Iterate
for (int i = 0; i < list.size(); i++) {
    for (int j = list.size() - 1; j >= i; j--) {
        // If i is j, then it's the same object and don't need to be compared.
        if (i == j) {
            continue;
        }
        // If the compared objects are equal, remove them from the copy and break
        // to the next loop
        if (list.get(i).equals(list.get(j))) {
            newList.remove(list.get(i));
            break;
        }
        System.out.println("" + i + "," + j + ": " + list.get(i) + "-" + list.get(j));
    }
}

This will remove all duplicates, leaving the last duplicate value as original entry. In addition, it will check each combination only once.

Using Java 8

Java Streams makes it even more elegant:

List<Integer> newList = oldList.stream()
    .distinct()
    .collect(Collectors.toList());

If you need to consider two of your objects equal based on your own definition, you could do the following:

public static <T, U> Predicate<T> distinctByProperty(Function<? super T, ?> propertyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(propertyExtractor.apply(t));
}

(by Stuart Marks)

And then you could do this:

List<MyObject> newList = oldList.stream()
    .filter(distinctByProperty(t -> {
        // Your custom property to use when determining whether two objects
        // are equal. For example, consider two object equal if their name
        // starts with the same character.
        return t.getName().charAt(0);
    }))
    .collect(Collectors.toList());

Futhermore

You cannot modify a list while an Iterator (which is usually used in a for-each loop) is looping through an array. This will throw a ConcurrentModificationException. You can modify the array if you are looping it using a for loop. Then you must control the iterator position (decrementing it while removing an entry).

摇划花蜜的午后 2025-01-03 07:41:38

或者 http://docs.oracle.com/javase/ 6/docs/api/java/util/SortedSet.html 如果您需要排序顺序..

编辑:从 http://docs.oracle.com/javase/6/docs /api/java/util/TreeSet.html,它将允许您在构造时传入 Comparator。您重写 add() 以使用您的比较器而不是 equals() - 这将使您能够灵活地创建根据您的比较器排序的不同集合,并且它们将实现你的“平等”策略。

不过,不要忘记 equals()hashCode()...

Or http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html if you need sort-order..

EDIT: What about deriving from http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html, it will allow you to pass in a Comparator at construction time. You override add() to use your Comparator instead of equals() - this will give you the flexibility of creating different sets that are ordered according to your Comparator and they will implement your "Equality"-Strategy.

Dont forget about equals() and hashCode() though...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文