在 ArrayList 中将每个项与其他每个项进行比较

25
我遇到了一个我本以为很简单的问题。
我需要将ArrayList中的每个项目与列表中的其他项目进行比较,而不将项目与自身进行比较。这不像调用equals()比较那么简单,它涉及到一些自定义逻辑,我已从下面的代码中省略了它。此外,ArrayList不应以任何方式更改。
我似乎遇到的问题是,一旦进入第二个循环,我不知道是否有另一个对象可以进行比较(因为它是一个变量大小的列表)。
for(int i =0; i< list.size(); i++){ 
    //get first object to compare to
    String a = list.get(i).getA();

    Iterator itr = list.listIterator(i + 1 ); // I don't know if i + 1 is valid
    while(itr.hasNext()){
        // compare A to all remaining items on list
    }
}

我觉得我可能用了错误的方法,欢迎提供建议或者如何更好地完成这个任务的技巧。


你说ArrayList不应该以任何方式被更改,因此列表的大小是不可变的:它是恒定的。因此,i+1将成为listIterator()的有效索引,因为保证i < list.size(),而listIterator接受一个包括list.size()在内的索引。一旦修复了微不足道的语法错误,你的代码应该可以直接运行。 - JB Nizet
太棒了,这个问题对我帮助很大! - sdot257
CR上,这可能适用于“看起来不太容易”类别(尤其是具有非对称的compare和通用的java.util.List<>)。从“比较列表L中的每个项目与[L]中的其他每个项目”的开始。 - greybeard
8个回答

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

6
这将进行比所需更多的比较,您将测试 item1 == item3 和 item3 == item1。 - Mike
1
是的,我刚意识到它在做一些不必要的比较,已经更新了代码。 - Kaleb Brasee
3
@Mike 不行,因为内层循环只获取外层循环当前索引位置之前的元素。 - Martin Klinke
2
我最初将其初始化为j = 0,然后进行了修复。 - Kaleb Brasee
1
另外,我只需要循环到list.size()-2。在循环期间,最后一个元素已经与所有其他元素进行了比较。 - chm
显示剩余5条评论

3
在内部使用for循环有什么问题,就像在外部一样?
for (int j = i + 1; j < list.size(); ++j) {
    ...
}

从Java 5开始,我通常只使用一两次迭代器。


1
你应该阅读《Effective Java》的第46条,它明确建议尽可能避免传统的for循环。 - Sean Patrick Floyd
@Sean Patrick Floyd,JVM可以使用内部机制来实现,如果需要的话。我不是说它目前正在使用,但是迭代器是最容易通过逃逸分析优化掉的东西。 - bestsss
2
@bestsss 我不是在谈论有效的字节码(在这种情况下,Josh Bloch也不是),而是关于可读性和非错误源代码。 - Sean Patrick Floyd

2

在某些情况下,这是最好的方法,因为您的代码可能已经做了一些更改,而j=i+1不会检查到这些更改。

for (int i = 0; i < list.size(); i++){  
    for (int j = 0; j < list.size(); j++) {
                if(i == j) {
               //to do code here
                    continue;
                }

}

}


“比较列表L中的每个项目与列表L中的其他项目”有一种解释。现在或许是考虑/提出基于java.util.stream的方法的时候了——遗憾的是,Stream必须是可克隆的并且提供一个有用的equals(),就像Iterator一样。 - greybeard

2
这段代码帮助我实现了以下行为:对于一个列表a、b、c,我应该比较ab、ac和bc,但任何其他的组合都是多余的/不必要的。
import java.util.*;
import static java.lang.System.out;

// rl = rawList; lr = listReversed
ArrayList<String> rl = new ArrayList<String>();
ArrayList<String> lr = new ArrayList<String>();
rl.add("a");
rl.add("b");
rl.add("c");
rl.add("d");
rl.add("e");
rl.add("f");

lr.addAll(rl);
Collections.reverse(lr);

for (String itemA : rl) {
    lr.remove(lr.size()-1);
        for (String itemZ : lr) {
        System.out.println(itemA + itemZ);
    }
}

循环的过程如下图所示:三角形比较可视化例子 或者是这样的:
   |   f    e    d    c    b   a
   ------------------------------
a  |  af   ae   ad   ac   ab   ·
b  |  bf   be   bd   bc   ·   
c  |  cf   ce   cd   ·      
d  |  df   de   ·         
e  |  ef   ·            
f  |  ·               

总比较次数是一个三角形数(n * n-1)/ 2


0
以下代码将使用contains()方法将每个项目与其他项目列表进行比较。for循环的长度必须大于更大列表的size(),才能比较两个列表的所有值。
List<String> str = new ArrayList<String>();
str.add("first");
str.add("second");
str.add("third");
List<String> str1 = new ArrayList<String>();
str1.add("first");
str1.add("second");
str1.add("third1");
for (int i = 0; i<str1.size(); i++)
{
System.out.println(str.contains(str1.get(i)));
}

输出结果为真 真 假


0

虽然这是一个老问题,但我想提供一个功能正确的版本,来源于Kaleb Brasee的代码。对于函数式编程纯粹主义者来说,这个版本比原版更快和更堆友好(顺便提一句)。

    IntStream.range(0, list.size())
        .forEach(i -> compare(list.get(i),
                               list.subList(i + 1, list.size())));
...

private void compare(final Element element, final List<Element> list) {

    list.stream()
        //whatever 

}

只需将其传递给一个集合 - jmisael56yahoocom

0
Arraylist<String> list =new Arraylist<>();
list.add("water");
list.add("air");
list.add("earth");
list.add("water");

Set<String> set = new LinkedHashSet<>();
      set.addAll(list);
    System.out.println(set.toString())

0

你可以像这样做。

for (int i = 0; i < arrayList.size(); i++) {
    for (int j = 0; j < arrayList.size(); j++) {
        if (i!=j &&  arrayList.get(i).YourObjectItem().equals(arrayList.get(j).YourObjectItem())) {
            //Your code will be here
        }

    }
}

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