Java比较两个列表


92

我有两个列表(不是Java列表,可以说两列)

例如

**List 1**            **Lists 2**
  milan                 hafil
  dingo                 iga
  iga                   dingo
  elpha                 binga
  hafil                 mike
  meat                  dingo
  milan
  elpha
  meat
  iga                   
  neeta.peeta    

我想要一个返回多少个相同元素的方法。对于此示例,它应该为3,并且应该返回列表的相似值和不同的值。

如果是,我应该使用哈希图,然后用什么方法获得结果?

请帮忙

PS:这不是学校作业:)因此,如果您只是指导我就足够了


请建议列表中的任何数据结构都不是Java列表或哈希图,也不是任何数据结构
user238384 2010年

1
请务必考虑在特殊情况下应采取的措施。列表可以包含两次相同的值吗?如果是这样,如果“ dingo”在两个列表中都出现两次,那么这是否算作两个共同元素还是仅一个?
JavadocMD 2010年

您可以修改列表之一吗?
Anthony Forloney,2010年

如何编辑?是的,每个列表可以多次包含相似的值
user238384 2010年

问题之后,标签下方应有一个编辑小链接。
OscarRyz 2010年

Answers:


159

编辑

这是两个版本。一种使用ArrayList,另一种使用HashSet

比较它们并从中创建您自己的版本,直到获得所需的内容。

这应该足以覆盖以下内容:

PS:这不是学校作业:)因此,如果您只是指导我就足够了

您的问题的一部分。

继续原始答案:

您可以为此使用java.util.Collection 和和 java.util.ArrayList

中的retainAll方法执行以下操作:

仅保留此集合中包含在指定集合中的元素

看到这个例子:

import java.util.Collection;
import java.util.ArrayList;
import java.util.Arrays;

public class Repeated {
    public static void main( String  [] args ) {
        Collection listOne = new ArrayList(Arrays.asList("milan","dingo", "elpha", "hafil", "meat", "iga", "neeta.peeta"));
        Collection listTwo = new ArrayList(Arrays.asList("hafil", "iga", "binga", "mike", "dingo"));

        listOne.retainAll( listTwo );
        System.out.println( listOne );
    }
}

编辑

对于第二部分(相似的值),可以使用removeAll方法:

删除此集合的所有元素,这些元素也包含在指定集合中。

第二个版本还为您提供了相似的值,并处理了重复的值(通过丢弃它们)。

这次Collection可能是a Set而不是a List(不同之处在于Set不允许重复的值)

import java.util.Collection;
import java.util.HashSet;
import java.util.Arrays;

class Repeated {
      public static void main( String  [] args ) {

          Collection<String> listOne = Arrays.asList("milan","iga",
                                                    "dingo","iga",
                                                    "elpha","iga",
                                                    "hafil","iga",
                                                    "meat","iga", 
                                                    "neeta.peeta","iga");

          Collection<String> listTwo = Arrays.asList("hafil",
                                                     "iga",
                                                     "binga", 
                                                     "mike", 
                                                     "dingo","dingo","dingo");

          Collection<String> similar = new HashSet<String>( listOne );
          Collection<String> different = new HashSet<String>();
          different.addAll( listOne );
          different.addAll( listTwo );

          similar.retainAll( listTwo );
          different.removeAll( similar );

          System.out.printf("One:%s%nTwo:%s%nSimilar:%s%nDifferent:%s%n", listOne, listTwo, similar, different);
      }
}

输出:

$ java Repeated
One:[milan, iga, dingo, iga, elpha, iga, hafil, iga, meat, iga, neeta.peeta, iga]

Two:[hafil, iga, binga, mike, dingo, dingo, dingo]

Similar:[dingo, iga, hafil]

Different:[mike, binga, milan, meat, elpha, neeta.peeta]

如果它不能完全满足您的需求,则可以为您提供一个良好的开始,因此您可以从这里开始。

给读者的问题:您将如何包括所有重复的值?


@Oscar,我的确切想法是,但我不确定是否可以修改的内容listOne,但无论如何还是要+1!
Anthony Forloney,2010年

@poygenelubricants你是指原始类型而不是泛型?为什么不?
OscarRyz 2010年

奥斯卡,您看到我的最新问题了吗?是否支持重复值?
user238384 2010年

@Oscar:java.sun.com/docs/books/jls/third_edition/html/… “强烈建议不要在将通用性引入Java编程语言后在代码中使用原始类型。未来的版本可能Java编程语言将禁止使用原始类型。”
多基因

2
@polygenelubricants回答已更新,可以处理重复项和原始类型。顺便说一句,.. future版本的Java ...永远不会发生。;)
OscarRyz 2010年


9

这些是真的列表(有序,重复项),还是集合(无序,无重复项)?

因为如果是后者,那么您可以使用a java.util.HashSet<E>,并使用便捷的在预期的线性时间内完成此操作retainAll

    List<String> list1 = Arrays.asList(
        "milan", "milan", "iga", "dingo", "milan"
    );
    List<String> list2 = Arrays.asList(
        "hafil", "milan", "dingo", "meat"
    );

    // intersection as set
    Set<String> intersect = new HashSet<String>(list1);
    intersect.retainAll(list2);
    System.out.println(intersect.size()); // prints "2"
    System.out.println(intersect); // prints "[milan, dingo]"

    // intersection/union as list
    List<String> intersectList = new ArrayList<String>();
    intersectList.addAll(list1);
    intersectList.addAll(list2);
    intersectList.retainAll(intersect);
    System.out.println(intersectList);
    // prints "[milan, milan, dingo, milan, milan, dingo]"

    // original lists are structurally unmodified
    System.out.println(list1); // prints "[milan, milan, iga, dingo, milan]"
    System.out.println(list2); // prints "[hafil, milan, dingo, meat]"

好吧,我真的不知道应该使用哪种数据结构。它有重复项。现在您可以看到更新的问题
user238384 2010年

它将从数据集中删除重复的值吗?因为我不想失去任何价值:(
user238384 2010年

@agazerboy:我试图解决两个问题。请随时要求更多的说明。
多基因

谢谢保利。我尝试了重复的程序,例如在第一个列表中我两次添加了“ iga”,但仍然返回3作为答案。虽然现在应该是4。因为列表1有4个相似的值。如果我多次添加一个条目,它应该可以工作。你说什么?还有其他数据结构吗?
user238384'5

6

使用Java 8 removeIf

public int getSimilarItems(){
    List<String> one = Arrays.asList("milan", "dingo", "elpha", "hafil", "meat", "iga", "neeta.peeta");
    List<String> two = new ArrayList<>(Arrays.asList("hafil", "iga", "binga", "mike", "dingo")); //Cannot remove directly from array backed collection
    int initial = two.size();

    two.removeIf(one::contains);
    return initial - two.size();
}

看起来不错,但是如果我想保持列表不变,就必须克隆其中一个列表,在某些情况下这是不希望的。
塞巴斯蒂安·达戈斯蒂诺

6

如果您正在寻找一种方便的方法来测试两个集合的相等性,则可以使用org.apache.commons.collections.CollectionUtils.isEqualCollection,它比较两个集合而不考虑其顺序。


4

在所有方法中,我发现使用org.apache.commons.collections.CollectionUtils#isEqualCollection是最好的方法。原因如下-

  • 我不必自己声明任何其他列表/集合
  • 我没有更改输入列表
  • 非常有效。它检查O(N)复杂度是否相等。

如果不可能具有apache.commons.collections依赖关系,由于效率高,我建议实施以下算法来检查列表是否相等。


3

简单的解决方案:

    List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "d", "c"));
    List<String> list2 = new ArrayList<String>(Arrays.asList("b", "f", "c"));

    list.retainAll(list2);
    list2.removeAll(list);
    System.out.println("similiar " + list);
    System.out.println("different " + list2);

输出:-

similiar [b, c]
different [f]

1

假设hash1hash2

List< String > sames = whatever
List< String > diffs = whatever

int count = 0;
for( String key : hash1.keySet() )
{
   if( hash2.containsKey( key ) ) 
   {
      sames.add( key );
   }
   else
   {
      diffs.add( key );
   }
}

//sames.size() contains the number of similar elements.

他想要的是相同键的列表,而不是多少个相同的键。我认为。
罗迪·卡西姆

感谢Stefan的帮助。是的Rosdi是正确的,您也是。我还需要类似值和相似值的总数。
user238384'5


-1
public static boolean compareList(List ls1, List ls2){
    return ls1.containsAll(ls2) && ls1.size() == ls2.size() ? true :false;
     }

public static void main(String[] args) {

    ArrayList<String> one = new ArrayList<String>();
    one.add("one");
    one.add("two");
    one.add("six");

    ArrayList<String> two = new ArrayList<String>();
    two.add("one");
    two.add("six");
    two.add("two");

    System.out.println("Output1 :: " + compareList(one, two));

    two.add("ten");

    System.out.println("Output2 :: " + compareList(one, two));
  }

1
当两个包含3个“一个”副本时,此解决方案将返回错误的结果。它会错误地产生真实的结果。
约瑟夫·菲茨杰拉德

感谢这个部分:()==()&& ls1.size ls2.size
Nouar

1
您认为摘要? true :false中需要任何理由吗?
Krzysztof Tomaszewski,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.