Java 交叉比较ArrayList元素并删除重复项
我有一个Java 交叉比较ArrayList元素并删除重复项,java,for-loop,arraylist,comparison,Java,For Loop,Arraylist,Comparison,我有一个ArrayList,它可能(也可能不)包含我需要从列表中删除的MyObject的重复项。我如何才能做到这一点,而不必像在两个for循环中迭代列表并交叉检查每个项目与其他每个项目一样检查重复项 我只需要检查每个项目一次,所以比较A:B就足够了-我不想再比较B:A,因为我已经这样做了 此外;我可以在循环时从列表中删除重复项吗?还是这会打破我的名单和循环 编辑:好的,我忘记了查看第一个答案时的一个重要部分:MyObject的副本不仅仅是用Java的方式表示Object.equals(Objec
ArrayList
,它可能(也可能不)包含我需要从列表中删除的MyObject的重复项。我如何才能做到这一点,而不必像在两个for循环中迭代列表并交叉检查每个项目与其他每个项目一样检查重复项
我只需要检查每个项目一次,所以比较A:B
就足够了-我不想再比较B:A
,因为我已经这样做了
此外;我可以在循环时从列表中删除重复项吗?还是这会打破我的名单和循环
编辑:好的,我忘记了查看第一个答案时的一个重要部分:MyObject
的副本不仅仅是用Java的方式表示Object.equals(Object),而是我需要能够使用我自己的算法来比较对象,由于MyObject
s的相等性是使用一种算法计算的,该算法以我需要实现的特殊方式检查对象的字段
此外,我不能在MyObject
中覆盖euqals
,因为有几种不同的算法实现不同的策略来检查两个MyObject
s的相等性-例如,有一个简单的HashComparer
和一个更复杂的euclidistancecomparer
,两者都是抽象比较器
,为公共抽象布尔值相等实现不同的算法(MyObject obj1,MyObject obj2)代码>对列表进行排序,重复项将彼此相邻,便于识别和删除。只需浏览列表,记住上一项的值,就可以将其与当前项进行比较。如果它们相同,请删除当前项
如果使用普通的for
-循环遍历列表,则可以控制当前位置。这意味着,当您删除一个项目时,您可以减小该位置(n--
),以便下一次循环将访问相同的位置(现在将是下一个项目)
您需要在排序中提供自定义比较吗?这并不难:
Collections.sort(myArrayList, new Comparator<MyObject>() {
public int compare(MyObject o1, MyObject o2) {
return o1.getThing().compareTo(o2.getThing());
}
});
Collections.sort(myArrayList,newcomparator(){
公共整数比较(MyObject o1,MyObject o2){
返回o1.getting().compareTo(o2.getting());
}
});
我编写这个示例是为了让getThing().compareTo()
代表您要做的任何事情来比较这两个对象。如果它们相同,则必须返回零的整数;如果o1大于o2,则必须返回大于1的整数;如果o1小于o2,则必须返回-1的整数。如果getting()
返回一个String
或一个Date
,您将被全部设置,因为这些类已经有了一个compareTo
方法。但是,您可以将需要的任何代码放入自定义的比较器中,创建一个集合,如果排序不重要,它将自动为您删除重复的代码
Set<MyObject> mySet = new HashSet<MyObject>(yourList);
Set mySet=newhashset(yourList);
实例化一个新的基于集合的集合HashSet。不要忘记为MyObject实现equals和hashcode
祝你好运 或者如果需要排序顺序
编辑:如何从中派生,它将允许您在构建时传入比较器。您重写add()
以使用比较器而不是equals()
——这将使您能够灵活地创建根据比较器排序的不同集合,它们将实现您的“相等”策略
如果对象顺序无关紧要,不要忘记equals()
和hashCode()
。
如果顺序不重要,您可以将列表中的元素放入集合
:
Set<MyObject> mySet = new HashSet<MyObject>(yourList);
Set mySet=newhashset(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));
}
}
//复制列表。
ArrayList newList=(ArrayList)list.clone();
//迭代
对于(int i=0;i=i;j--){
//如果我是j,那么它是同一个对象,不需要比较。
如果(i==j){
继续;
}
//如果比较的对象相等,请将其从复制和打断中删除
//到下一个循环
if(list.get(i).equals(list.get(j))){
newList.remove(list.get(i));
打破
}
System.out.println(“+i+”,“+j+”:“+list.get(i)+”-“+list.get(j));
}
}
这将删除所有重复项,将最后一个重复值保留为原始条目。此外,它将只检查每个组合一次
使用Java8
Java Streams使其更加优雅:
List<Integer> newList = oldList.stream()
.distinct()
.collect(Collectors.toList());
List 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));
}
公共静态谓词distinctByProperty(函数propertyExtractor){
Set seen=ConcurrentHashMap.newKeySet();
返回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());
List newList=oldList.stream()
.过滤器(distinctByProperty)(t->{
//确定两个对象
例如,考虑两个对象是否相等,如果它们的名字相同
//以相同的字符开头。
返回t.getName().charAt(0);
}))
.collect(Collectors.toList());
此外
当迭代器(通常用于for-each循环)在数组中循环时,不能修改列表。这将抛出一个ConcurrentModificationException
。如果正在循环数组,则可以修改该数组