使用迭代器在Java中从列表中删除重复项

3

我正在为我的Java入门课程的作业问题努力工作,我们需要在不使用集合或.contains()方法的情况下从列表中删除重复项。基本上只使用迭代器和.equals()方法。我的代码如下:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


public class sample {
public static void main(String[] args) throws BadListException {
    List<String> myList = new ArrayList<String>();
    myList.add("A");
    myList.add("B");
    myList.add("B");
    myList.add("C");
    myList.add("B");
    myList.add("D");


    unique(myList);
    System.out.println(myList);


}
public static List<String> unique( List<String> items ) throws BadListException { 

    List<String> newList = new ArrayList<String>();
    Iterator<String> itr = items.listIterator();

    // If items is null, throw a BadListException. 

    if (items == null){
        throw new BadListException();
    }
    // If items is empty, return a new empty list. 

    if (items.isEmpty()){
        return newList;
    }

    // Otherwise create and return a new list that contains the items 
    // in L with all duplicates removed.  
    // Example: items: "A","B","C"              result: "A","B","C" 
    // Example: items: "A","A","A"              result: "A" 
    // Example: items: "A","B","B","C","A","D"  result: "A","B","C","D" 

    while (itr.hasNext()){
        for (int i = 0; i < items.size()-1; i++){
            if (itr.next().equals(items.get(i))){
                itr.remove();
            }
        }

    }
    items = newList;
    return newList;

如果有人能够解释一下我做错了什么以及我应该怎样做,那将非常有帮助。请注意,由于这是为了准备测试,所以我希望得到解释而不仅仅是正确的代码。


1
非常好的表达“作业问题”的方式!现在你能告诉我们你遇到了什么问题或困难吗? - Floris
1
你正在返回 newList,而你从未更改它。 - El Hocko
首先,集合中的第一项总是被删除(我认为这是因为正在迭代的第一个元素将始终等于自身,为了避免这种情况,我可以从索引1开始而不是从索引0开始循环,这将解决问题)。但更重要的是,当我在除了紧挨着该项本身之外的任何位置添加重复项时(例如A、B、C、B),程序就会无限期地运行下去。只是澄清一下:如果我将所有重复项都放在一起,并且返回newList而没有重复项,则程序按预期工作。 - user1542396
10个回答

5
不要解释发生了什么错误,建议使用调试器查看程序当前正在执行的操作。特别地,每次调用iter.next()时,请查看迭代器返回的内容。
正确解决方案的提示:
  1. 您需要使用多个迭代器……
  2. 您没有将任何东西放入要返回的列表中。
  3. 您需要确定是创建和返回新列表还是从现有列表中删除元素。同时进行这两个操作没有意义。

以后,当您提出问题时,应提供更好的陈述,说明程序实际上应该执行什么操作。例如:
  • 您没有说明unique方法是否应从参数列表中删除元素或返回一个仅包含唯一元素的新列表。
  • 您没有说明列表中元素的顺序是否重要。
  • 您没有说明是否可以更改输入列表……或者不行。
在解决此类问题时,所有这些都很重要。尤其是在现实世界中。即使您的任务没有说明这些事情,您仍然需要确定自己的代码的预期工作方式,并使用javadoc注释进行文档化。

3
  • i==0 时,iterator.next()get(i) 将是相同的元素,所以您只是删除了它。
  • 对于同一个列表,最好不要在 for 循环中使用 iterator.remove()
  • 您没有向 newList 添加任何内容,而只是简单地将其返回。
  • 针对此任务的建议:

您可以先 排序 列表,然后遍历它,如果一个元素等于其前一个元素,则删除该元素。如果您想要,当然可以创建一个新列表来保存这些独特的元素。

我的看法


对列表进行排序会扰乱列表元素的顺序。问题在于原帖作者没有正确说明该方法的目的...他现有的代码存在“多重人格障碍”。 - Stephen C
@StephenC 你说得对。排序会改变e的顺序。那么问题/任务必须定义如何去除重复项。例如,“始终保留第一个/最后一个/n个元素,如果发现重复项”。否则,顺序也可能被“改变”。无论如何,如果问题定义得好,解决方案就不难实现。不过,保留nth元素可能有些棘手。 - Kent

2
以下是解决方案:
    List<String> list = Lists.newArrayList("1","4","8","1","4","5","1");
    Collections.sort(list);

    Iterator<String> itr = list.iterator();
    String old = itr.next();
    while(itr.hasNext())
    {
        String next = itr.next();

        if(old.equals(next))
        {
            itr.remove();
        }
        old = next;
    }

1
你可以创建自己的迭代器,其目的是仅返回重复值一次。
public class NoDuplicatesIterator<T> implements Iterator<T> {

    private final List<T> array;
    private final List<T> encountered;
    private int index = 0;

    public NoDuplicatesIterator(List<T> array) {
        this.array = array;
        encountered = new ArrayList<>();
    }

    @Override
    public boolean hasNext() {
        if (index > array.size() - 1) {
            return false;
        }

        while (encountered.contains(array.get(index)) && index < array.size() - 1) {
            index++;
        }

        return index <= array.size() - 1;
    }

    @Override
    public T next() {
        encountered.add(array.get(index));
        return array.get(index++);
    }

}

使用方法:

public class Main {

    public static void main(String[] args) {
        List<Integer> array = Arrays.asList(new Integer[]{100, 2, 2, 1, 1, 2, 3, 3, 15, 4, 4, 5, 6, 7, 7, 8, 99, 99, 100, 99, 2, 77, 23, 14, 2, 15});
        NoDuplicatesIterator<Integer> it = new NoDuplicatesIterator(array);

        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }

}

1

遍历列表并删除元素会改变列表... 如果您查看了元素“4”并决定将其删除,那么您下一个要查看的元素是什么?提示:它不是原始元素“5”,而是新元素“5”...


0

非常简单

方法是...首先检查列表是否有该值,如果有,则跳过添加它,如果没有,则添加元素,您将获得唯一的列表...而不是运行密集的迭代器操作 :)

示例

List<Integer> listOfUserIds = new ArrayList<Integer>();
     Integer UserIdCheck = 0;
     for (User userTest : userCollection) {
     UserIdCheck = userService.getUserByRegionCode(userTest.                      .getRegionId());
    if (!listOfUserIds.contains(UserIdCheck)) //check befor adding listOfUserIds.add(UserIdCheck);
        }
  } 
  return listOfUserIds.toString().replace("[", "").replace("]", ""); // if u like can remove [ and ] from the list and simply return a string like "4,5,6" 

0
code extract without using iterator 

import java.util.ArrayList;
import java.util.List;

  public class Test {
    final static List<String> str = new ArrayList<String>();
    public Test(){

        str.add("A");
        str.add("B");
        str.add("C");
        str.add("C");
        str.add("D");
        str.add("A");
        str.add("B");
        str.add("C");
        str.add("C");
        str.add("D");
        str.add("B");
        str.add("C");
        str.add("B");
        str.add("C");
        str.add("C");
        str.add("D");
        str.add("B");
        str.add("C");
        str.add("C");
        str.add("C");
        str.add("D");
        System.out.println(str);


    }

    public  List<String> rmovedDuplicate(List<String> str){

        List<String> finalList = new ArrayList<String>();

        for(int i =0; i<str.size();i++){
            for (int j=i+1; j<str.size();j++){
                if(str.get(i).equals(str.get(j))){
                    str.remove(j);
                    i=0;

                }
            }
        }

        System.out.println("final list :"+str);
        return str;
    }

    public static void main(String args[]){
        Test t = new Test();
        t.rmovedDuplicate(str);
    }

}

@kishor:Set 的功能是去除重复项。如果您正在使用 set,则无需使用 list 并转换为 set,可以直接使用 set。当您将元素添加到 set 中时,其中将得到非重复元素。 - Vidyarani Shinde

0

另一种简单的方法如下所示。

import java.util.HashSet;
import java.util.List;
import java.util.Set;public class Main {

    /**
     * @param args
     */
    public static void main(String args[]) throws SQLException {
        System.out.println("Entered Main");
        Test();
        System.out.println(str);
        set.addAll(str);
        System.out.println(set);
        str.clear();
        str.addAll(set);
        System.out.println(str);
    }
    final static List<String> str = new ArrayList<String>();
    final static Set<String> set = new HashSet<String>();
    public static void Test(){

        str.add("A");
        str.add("B");
        str.add("C");
        str.add("C");
        str.add("D");
        str.add("A");
        str.add("B");
        str.add("C");
        str.add("C");
        str.add("D");
        str.add("B");
        str.add("C");
        str.add("B");
        str.add("C");
        str.add("C");
        str.add("D");
        str.add("B");
        str.add("C");
        str.add("C");
        str.add("C");
        str.add("D");
        System.out.println(str);
    }

填充列表的测试方法是从Vidyarani Shinde的答案中复制的。


@Vidyarani:是的,但由于他需要数据以列表形式呈现,所以我只是将其再次添加到列表中。 - Kishor Raskar

0

我曾经尝试过使用高级的 for each 循环,也尝试了将 ArrayList 转换为 HashSet,再转换回 ArrayList。这两种解决方案都可以正常工作。你可以选择任何一种。

public static void main(String[] args) {
    ArrayList<String> wordDulicate = new ArrayList<String>();

    wordDulicate.add("Tom");
    wordDulicate.add("Jones");
    wordDulicate.add("Sam");
    wordDulicate.add("Jamie");
    wordDulicate.add("Robie");
    wordDulicate.add("Helen");
    wordDulicate.add("Helen");
    wordDulicate.add("Helen");
    wordDulicate.add("Helen");
    wordDulicate.add("Tom");
    wordDulicate.add("Troy");
    wordDulicate.add("Mika");
    wordDulicate.add("Tom");

    System.out.println("Array List size"+wordDulicate.size());

    ArrayList<String> nonDuplicat=new ArrayList<String>(new HashSet<String>(wordDulicate));

    System.out.println("Array List size"+nonDuplicat.size());
    ArrayList<String> nonDuplicatThroughIterator=new ArrayList<String>();

    for(String each:wordDulicate){
        if(!nonDuplicatThroughIterator.contains(each))
            nonDuplicatThroughIterator.add(each);
    }
    System.out.println("Array List size"+nonDuplicatThroughIterator.size());

}

-1

假设ArrayList实现了ListADTArrayListArrayListIterator类按预期实现,并且BadListException是一个具有零参数构造函数的未经检查的异常。还要假设空元素不能添加到列表中。

我必须完成指定的Java方法,利用迭代器。我的解决方案应满足以下要求:

  1. 必须明确使用迭代器遍历列表(即,不得使用for循环或Java的扩展-for循环)
  2. 不得使用contains方法
  3. 可以使用在在线阅读中描述的任何ListADT方法(除了contains),包括ListADT.iterator(),但不得使用那里未提到的任何其他List方法
  4. 不得修改参数的内容。

该函数的骨架:

public static ListADT<String> union(ListADT<String> list1, ListADT<String> list2) {
    // If list1 or list2 (or both list1 and list2) is null, throw a BadListException. 
    // If list1 and list2 are both empty, return a new empty list.
    // If list1 is empty (but not list2), return a new list containing the strings in
    //     list2 with all duplicates removed.
    // If list2 is empty (but not list1), return a new list containing the strings in
    //     list1 with all duplicates removed.
    // Otherwise, create and return a new list that contains the strings in list1 and
    //     the strings in list2 with all duplicates removed.
    //
    // Examples:
    //  list1: "a","b","c"          list2: "d","e","f"      result: "a","b","c","d","e","f"
    //  list1: "a","c","b","d"      list2: "e","d","a","f"  result: "a","c","b","d","e","f"
    //  list1: "a","b","c","b","a"  list2: "c","a","b"      result: "a","b","c"
    //
    // Note: the list returned does not need to be in any particular order

我必须确保我的解决方案仅使用在线阅读中描述的ListADT接口中的方法(包括迭代器方法,如上所述)。

我该怎么做?


你应该另外提出一个新问题。如果你把你的问题作为旧问题的答案发布,那么你不会得到回答。不过,我已经编辑了你的“答案”,因此你可以将它复制并粘贴成一个格式合理的问题。完成这些后,你应该删除此内容。 - zondo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接