【问题标题】:Iterate over a list using an iterator and compare consecutive elements使用迭代器迭代列表并比较连续元素
【发布时间】:2016-12-11 22:18:23
【问题描述】:

我想比较单个列表中的每个元素,下面的代码提供了我的解决方案:

for (int i = 0; i < list.size(); i++) {
    for (int j = i + 1; j < list.size(); j++) {
        // compare 
    }
}

它比较元素索引,例如比较四个元素:

0 to 1
0 to 2
0 to 3
1 to 2
1 to 3
2 to 3

我想使用迭代器实现与上述相同的目的。我使用迭代器的实现:

int i = 0;
for (Iterator<Tuple> it = list.iterator(); it.hasNext();) {
    Tuple tB = null;
    Tuple tA = it.next();

    for(int j = 0; j == i; j++) {
        try {
            tB = it.next();

            if(tA.Username.equals(tB.Username) && .....) {
                System.out.println("Match");
            } else {
                System.out.println("Not Matched");
            }
            i++;
        } catch(NoSuchElementException exc) {
            throw exc;
        }   
    }
}

Tuple 是一个具有一些字符串属性的类。

此代码仅将第一个元素与其他元素进行比较并抛出NoSuchElementException,但我想从内部 for 循环移动到外部 for 循环以继续遍历。我怎样才能做到这一点?

【问题讨论】:

  • 你需要一个内部迭代器和一个外部迭代器。
  • 直接访问有什么问题?您的代码已经可以使用了。
  • @Bohemian 我正在为 apache-pig 编写 java udf,出于测试目的,我在普通 java 上尝试了它,这里的直接访问效果很好,但我使用了 apache pig 的 Tuple 类并从中列出了它。我无法使用 i.get(arg) 方法访问属性..我能够在普通 java.Tuple 类实现 Iterator 接口中实现,所以我尝试用 java 进行测试。

标签: java list loops iterator


【解决方案1】:

您好,由于您的 it.next() 在内部 for 循环中,您得到了异常。你需要第二个迭代器。

 for (Iterator<Tuple> it = list.iterator(); it.hasNext();) 
{
       Tuple tA = it.next();
       List<Tuple> tmpList = new ArrayList<Tuple>(list);
       tmpList.remove(tA);
  for( Iterator<Tuple> it2 = tmpList.iterator(); it2.hasNext();)     {
        try{
            Tuple tB=it2.next();

            if(tA.Username.equals(tB.Username) && .....)
            {
                System.out.println("Match");
            }
            else
            {
                System.out.println("Not Matched");
            }
            i++;
        }
        catch(NoSuchElementException exc)
        {
            throw exc;
        }   
    }
}

【讨论】:

  • 它返回两个新的迭代器
  • 代码将每个对象与另一个对象进行比较。它还与自身进行比较...如何防止相同的索引对象不相互比较?我正在尝试相同
  • 您可以使用新列表并从中删除元素。已在帖子中编辑。
  • 这里将 item1 与 item2 进行比较,然后将 item2 再次与 item2 进行比较......那么我们如何才能停止这种比较
【解决方案2】:

为了赞美shsvd98 answer,您可以使用ListIterator 而不是IteratorListIterator 扩展 Iterator 并提供更多功能。

例如,以下代码与您的第一个代码块完全相同。它也不会将元素与自身进行比较,也无需在每次外部 for 循环迭代后创建另一个 List

Tuple tA = null;
Tuple tB = null;

for (ListIterator<Tuple> one = list.listIterator(); one.hasNext();) {
    // set 'tA' here, not in the nested for loop
    tA = one.next();

    // initialize 'two' with the next index of 'one'
    for(ListIterator<Tuple> two = list.listIterator(one.nextIndex()); two.hasNext();) {
        // set 'tB' here
        tB = two.next();

        // debug line used in output below this code block
        // System.out.print("tA:" + tA + " to tB:" + tB + " ");

        try {
            if(tA.username.equals(tB.username)) {
                System.out.println("Match");
            } else {
                System.out.println("Not Matched");
            }
        } catch(NoSuchElementException exc) {
            throw exc;
        }  

    }
}

我运行了上面的代码,将Tuple 换成了String

Populated ArrayList with ["a", "b", "c", "b"]

Output:
tA:a to tB:b Not Matched
tA:a to tB:c Not Matched
tA:a to tB:b Not Matched
tA:b to tB:c Not Matched
tA:b to tB:b Match
tA:c to tB:b Not Matched

如果您对使用ListIterator 优于Iterator 的好处感到好奇,那么ListIterator documentation 可以提供更多见解。

【讨论】: