简体   繁体   English

删除 ArrayList 中的重复项 - Java

[英]Remove duplicates in ArrayList - Java

I have some problem with my Java code.我的 Java 代码有问题。 I'm supposed to use loops and not any other method.我应该使用循环而不是任何其他方法。 Say that my ArrayLis t contains of说我的ArrayLis包含

[Dog Cat Dog Dog Cat Dog Horse] 【狗猫狗狗猫狗马】

My goal is also to remove the copies of Dog and Cat so my final results equals我的目标也是删除 Dog 和 Cat 的副本,以便我的最终结果等于

[Dog Cat Horse] 【狗猫马】

public void removeDouble(){

int counter = 0;
for (int i = 0 ; i < animals.size(); i++) { 
    for (int j = 1+i;  j < animals.size() ; j++)  
        //don't start on the same word or you'll eliminate it.
        if ( animals.get(j).equals( animals.get(i) )  ) {
            animals.remove(animals.get(j));
           counter++;

        }                                
    } 
}

It feels like the "logic" is correct but my code does not work very well.感觉“逻辑”是正确的,但我的代码不能很好地工作。 Can somebody help me a little?有人可以帮我一点吗?

You can do like this.你可以这样做。

 ArrayList<String>list=new ArrayList<>();
    list.add("A");
      list.add("B");
      list.add("C");
      list.add("A");
    System.out.println("Before "+list); // output[A,B,C,A]


    Set<String> listWithoutDuplicates = new LinkedHashSet<String>(list);
     list.clear();

    list.addAll(listWithoutDuplicates);
    System.out.println("list without duplicates : " + list);// output[A,B,C]

The logic for the inner loop is incorrect.内循环的逻辑不正确。

You will skip items every time you have the same item appear consecutively in the list.每次在列表中连续出现相同的项目时,您将跳过项目。

Say you had "dog", "dog", "dog", "cat".假设你有“狗”、“狗”、“狗”、“猫”。 When you remove the "dog" at index 1, the list now becomes "dog", "dog", "cat".当您删除索引 1 处的“狗”时,列表现在变为“狗”、“狗”、“猫”。

The problem is that your "j" index is now incremented to 2 so the next test will access the "cat" item, not the "dog" item.问题是您的“j”索引现在增加到 2,因此下一个测试将访问“cat”项目,而不是“dog”项目。 So every time you remove an item you are skipping the next item in the list which is why you get inconsistent results.因此,每次删除一个项目时,您都会跳过列表中的下一个项目,这就是您得到不一致结果的原因。

The solution is to either:解决方案是:

  1. decrement the j variable every time you remove an item每次删除项目时递减 j 变量
  2. start the inner loop from the end of the list and count down backwards toward 0.从列表的末尾开始内循环,然后倒数到 0。

It would be simpler to start from the end of the list and decrement the counter.从列表的末尾开始并递减计数器会更简单。 After removing the double at i, we can break without checking the whole string, because further doubles will be detected when i reaches j.删除 i 处的双精度值后,我们可以在不检查整个字符串的情况下中断,因为当 i 到达 j 时将检测到进一步的双精度值。

    for(int i=animals.size()-1; i>0; i--) {
        for(int j=i-1; j>=0; j--) {
            if(animals.get(i).equals(animals.get(j))) {
                animals.remove(i);
                break;
            }
        }
    }

Moving backwards avoids the problem as you move forward the indexes have changed because you removed earlier elements (and you failed to adjust the index to take that into account).向后移动可以避免在向前移动时出现问题,因为您删除了较早的元素(并且您未能调整索引以将其考虑在内),因此索引已更改。

Another problem with your logic you were using remove(object) rather than remove(index), which causes the first matching object to be removed.您使用的是 remove(object) 而不是 remove(index) 的逻辑的另一个问题,这会导致第一个匹配的对象被删除。 However, based on expected output, you want to preserve the order of the first matching objects.但是,根据预期输出,您希望保留第一个匹配对象的顺序。 So instead you should have removed the last matching object, via index.因此,您应该通过 index.html 删除最后一个匹配的对象。


If you want to move forward rather than backwards, but you don't wish to make adjustments to the index after a removal, it is possible to make use of iterator's remove method:如果您想向前移动而不是向后移动,但您不想在删除后对索引进行调整,则可以使用迭代器的 remove 方法:

    for(int i=0; i<animals.size()-1; i++) {
        ListIterator<?> iter = animals.listIterator(i+1);
        while(iter.hasNext()) {
            if(animals.get(i).equals(iter.next())) {
                iter.remove();
            }
        }
    }

Unfortunately the outer loop here cannot use an iterator because that would result in a ConcurrentModificationException.不幸的是,这里的外循环不能使用迭代器,因为这会导致 ConcurrentModificationException。


Finally, you could also use a subList to solve it with a single explicit loop:最后,您还可以使用 subList 通过单个显式循环来解决它:

    for(int i=0; i<animals.size()-1; i++) {
        animals.subList(i+1, animals.size()).removeIf(animals.get(i)::equals);
    }

In Java 8 we can use Stream API to remove duplicates, Like below snippet.在 Java 8 中,我们可以使用 Stream API 删除重复项,如下所示。

List<String> uniqueAnimal = animal.stream().distinct().collect(Collectors.toList()); 

Working Example.工作示例。

import java.util.*;
import java.util.stream.Collectors;
public class MyClass {
    public static void main(String args[]) {
        List<String> animal = new ArrayList<>();
        animal.add("Dog");
        animal.add("Cat");
        animal.add("Dog");
        animal.add("Dog");
        animal.add("Cat");
        animal.add("Dog");
        animal.add("Horse");
        List<String> uniqueAnimal = animal.stream().distinct().collect(Collectors.toList());
        System.out.println("animal =>  " + animal);
        System.out.println("uniqueAnimal =>  " + uniqueAnimal);
    }
}

With Java 8 stream you can do as follows:使用 Java 8 流,您可以执行以下操作:

public class RemoveDuplicates {

public static void main(String[] args) {
    removeDuplicateElements(Arrays.asList("Dog","Cat","Dog","Dog","Cat","Dog","Horse"));
  }

private static void removeDuplicateElements(List<String> animalList)
  {
    animalList.stream().distinct().collect(Collectors.toList()).forEach(System.out::println);
  }

}

Your current code -您当前的代码 -

for (int i = 0; i < animals.size(); i++) {
     for (int j = 1 + i; j < animals.size(); j++)
         if (animals.get(j).equals(animals.get(i))) {
             animals.remove(animals.get(j)); // this would remove the current element only if the previous element is same as the current element
             // since the index `j` would change post that 
         }
     }
}

A simple way to do this is一个简单的方法是

animals.stream().distinct().collect(Collectors.toList()).forEach(System.out::print);

Or using -或使用 -

Set<String> distAnimal = new HashSet<>(animals);
System.out.println(Arrays.toString(distAnimal.toArray()));

Your removing the items as you are iterating over them, have an array that holds indexes, and when you find a double, add the index to the indexes array.您在迭代它们时删除项目,有一个包含索引的数组,当您找到双精度值时,将索引添加到索引数组中。 Iterate over the indexes array and delete from the animals arraylist.迭代索引数组并从动物数组列表中删除。

Thanks for all the answers.感谢所有的答案。 I still have a few problems, this is what i have came up with:我仍然有一些问题,这是我想出的:

    int counter =0;
for(int i = 0 ; i < animals.size() ; i++){
    for(int j = animals.size() -1 ; j>i ; j--){
        if(animals.get(j).equals(animals.get(i))){
            counter++;

}

    }
}
    System.out.println(counter);
}

So now I'm starting the inner loop from the end of the ArrayList.所以现在我从 ArrayList 的末尾开始内部循环。 Priority right now is only the get the loop working and then add remove etc.现在的优先事项只是让循环工作,然后添加删除等。

Cheers!干杯!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM