2016-08-22 98 views
3

我目前正在尝试创建一个方法来确定一个ArrayList(a2)是否包含一个ArrayList(a1),如果两个列表都包含重复值(containsAll不起作用仿佛一个ArrayList包含重复的值,那么它会返回true,无论值的数量)的Java:看ArrayList是否包含重复值的ArrayList

这是我有:(我相信但它会工作,我不能在for循环使用卸下摆臂)

public boolean isSubset(ArrayList<Integer> a1, ArrayList<Integer> a2) { 
    Integer a1Size= a1.size(); 
    for (Integer integer2:a2){ 
     for (Integer integer1: a1){ 
      if (integer1==integer2){ 
       a1.remove(integer1); 
       a2.remove(integer2); 
       if (a1Size==0){ 
        return true; 
       } 
      } 
     } 
    } 
    return false; 
} 

感谢您的帮助。

+0

这两个列表中的项目的顺序很重要吗? – GuiSim

+1

'a1Size'的值只被计算一次(在循环之前),所以基于它的值的逻辑是没有意义的 –

+3

若要从arrayList中移除使用迭代器 –

回答

1

,如果你想删除列表中的元素,你有两个选择:

  • 叠代复制
  • 使用并发列表实现

还看到:

http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedList-java.util.List-

btw为什么你不重写contains方法?

在这里,你用简单的物体,像“整数”,当你将使用列表<什么SomeComplexClass> ??

例如用迭代器来副本中删除:

List<Integer> list1 = new ArrayList<Integer>(); 
    List<Integer> list2 = new ArrayList<Integer>(); 

    List<Integer> listCopy = new ArrayList<>(list1); 
    Iterator<Integer> iterator1 = listCopy.iterator(); 
    while(iterator1.hasNext()) { 
     Integer next1 = iterator1.next(); 
     Iterator<Integer> iterator2 = list2.iterator(); 
     while (iterator2.hasNext()) { 
      Integer next2 = iterator2.next(); 
      if(next1.equals(next2)) list1.remove(next1); 
     } 
    } 

也看到这个答案关于迭代器:

Concurrent Modification exception

也不要使用==操作符来比较的对象: )改为使用相等的方法

约使用的removeAll()和其他类似的方法:

记住,实现单接口多类不覆盖从列表界面中的所有方法 - 这样你就可以不支持的操作异常结束了 - 这样就在这种情况下,我更喜欢“低级别”二进制/线性/混合搜索。

和复杂的类的对象进行比较,你需要重写平等和hashCode方法

F你想删除重复值,简单地把该ArrayList(S)到一个HashSet。它将根据对象的equals()删除重复项。 - 奥尔加

在Java中,HashMap的工作原理是利用的hashCode找到一个桶。每个存储桶都是存储在该存储桶中的项目列表。扫描项目,使用等于比较。添加项目时,一旦达到特定的负载百分比,就会调整HashMap的大小。

所以,有时它必须与几个项目进行比较,但通常比O(n)更接近O(1)。

总之 - 没有必要使用更多的资源(内存)和“利用”不必要的类 - 因为随着项目数量的增长,哈希映射“get”方法变得非常昂贵。

hashCode -> put to bucket [if many item in bucket] -> get = linear scan 

    so what counts in removing items ? 

equals和hasCode的复杂性和适当的算法,用于迭代

1

更新

我觉得你的问题的最明确的声明是在您的意见之一:

是的,例子“例子:[狗,猫,猫,鸟]是 c包含[猫,狗]是假的,但包含[猫,猫,狗]是真的吗?“ 正是我想要实现的。

所以真的,你不是在寻找一个“子集”,因为这些不是集合。它们可以包含重复的元素。你真正想说的是你想看看a1是否包含相同数量的a2的所有元素。

达到此目的的一种方法是统计两个列表中的所有元素。我们可以用这种方法得到这样的计数:

private Map<Integer, Integer> getCounter (List<Integer> list) { 
    Map<Integer, Integer> counter = new HashMap<>(); 
    for (Integer item : list) { 
     counter.put (item, counter.containsKey(item) ? counter.get(item) + 1 : 1); 
    } 
    return counter; 
} 

我们将重命名你的方法被调用containsAllWithCounts(),它将使用getCounter()作为帮手。您的方法也将接受List对象作为其参数,而不是ArrayList对象:将参数指定为接口而不是实现是一种很好的做法,因此您不必使用ArrayList类型。

考虑到这一点,我们只是扫描项目的计数a2,看看他们是相同的a1

public boolean containsAllWithCounts(List<Integer> a1, List<Integer> a2) { 
     Map<Integer,Integer> counterA1 = getCounter(a1); 
     Map<Integer,Integer> counterA2 = getCounter(a2); 

     boolean containsAll = true; 
     for (Map.Entry<Integer, Integer> entry : counterA2.entrySet()) { 
      Integer key = entry.getKey(); 
      Integer count = entry.getValue(); 
      containsAll &= counterA1.containsKey(key) && counterA1.get(key).equals(count); 
      if (!containsAll) break; 
     } 

     return containsAll; 
    } 

如果你愿意,我可以重写这段代码来处理任意类型,不仅仅是Integer对象,使用Java泛型。此外,所有代码都可以使用Java 8流(我原来使用 - 请参阅下面的注释)缩短。请在评论中告诉我。

+0

@ sparc-spread当我们使用java 7,6时呢?顺便说一句,也许他应该从最容易的事情开始? – ceph3us

0

我知道这也许是电枢十岁上下,但...

无需去除两个列表中的项目,所以,只是把它从一个列表

public boolean isSubset(ArrayList<Integer> a1, ArrayList<Integer> a2) { 
    for(Integer a1Int : a1){ 
     for (int i = 0; i<a2.size();i++) { 
      if (a2.get(i).equals(a1Int)) { 
       a2.remove(i); 
       break; 
      } 
     } 
     if (a2.size()== 0) { 

      return true; 
     } 
    } 
    return false; 
} 
0

如果你想删除重复值,只需将数组列表放到HashSet中即可。它将根据对象的equals()删除重复项。

相关问题