我有ArrayList<MyObject>
可能(或可能不)包含我需要从列表中删除的MyObject
重复项。如果我在两个for循环中迭代列表并与每个其他项交叉检查每个项目,我怎么能这样做,我不必像我一样检查重复两次。
我只需要检查每个项目一次,因此比较A:B
就足够了 - 我不想再次比较B:A
,因为我已经这样做了。
此外;我可以在循环时从列表中删除重复项吗?或者会以某种方式打破列表和我的循环?
编辑:好的,我在第一个答案中忘记了一个重要的部分:MyObject
的重复不仅仅意味着在Java方式中意味着 Object.equals(Object ),但我需要能够使用我自己的算法比较对象,因为MyObject
的相等性是使用一种算法来计算的,该算法以我需要实现的特殊方式检查对象的字段!
此外,我不能仅仅覆盖euqals
中的MyObject
,因为有几种不同的算法可以实现不同的策略来检查两个MyObject
的相等性 - 例如有一个简单的HashComparer
和一个更复杂的EuclidDistanceComparer
,AbstractComparers
为public abstract boolean isEqual(MyObject obj1, MyObject obj2);
实现了不同的算法
答案 0 :(得分:4)
对列表进行排序,重复项将彼此相邻,使其易于识别和删除。只需浏览列表,记住上一个项目的值,以便将其与当前项目进行比较。如果它们相同,请删除当前项目。
如果您使用普通的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()
返回String
或Date
,则您将全部设置,因为这些类已经有compareTo
方法。但您可以在自定义Comparator
中添加所需的任何代码。
答案 1 :(得分:4)
创建一个集合,如果排序不重要,它将自动删除重复项。
Set<MyObject> mySet = new HashSet<MyObject>(yourList);
答案 2 :(得分:2)
实例化一个新的基于集合的集合HashSet。不要忘记为MyObject实现equals和hashcode。
祝你好运!答案 3 :(得分:1)
如果订单不重要,您可以将列表的元素放入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 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));
}
然后你可以这样做:
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());
当Iterator
(通常在for-each循环中使用)循环遍历数组时,无法修改列表。这将抛出ConcurrentModificationException
。如果使用for循环对其进行循环,则可以修改该数组。然后,您必须控制迭代器位置(在删除条目时递减它)。
答案 4 :(得分:0)
或http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html如果您需要排序顺序..
编辑:如果从http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html派生,它将允许您在施工时传入比较器。您覆盖add()
以使用比较器代替equals()
- 这将使您可以灵活地创建根据比较器订购的不同套件,并且他们将实施您的“平等” - 策略。
不要忘记equals()
和hashCode()
虽然......