【问题标题】:Java: See if ArrayList contains ArrayList with duplicate valuesJava:查看 ArrayList 是否包含具有重复值的 ArrayList
【发布时间】:2016-12-28 10:42:45
【问题描述】:

我目前正在尝试创建一个方法来确定 ArrayList(a2) 是否包含 ArrayList(a1),因为这两个列表都包含重复值(containsAll 不能像 ArrayList 包含重复值一样工作,那么它无论值的数量如何,都会返回true)

这就是我所拥有的:(我相信它会起作用,但是我不能在 for 循环中使用 .remove)

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;
}

感谢您的帮助。

【问题讨论】:

  • 两个列表中项目的顺序重要吗?
  • a1Size 的值仅被计算一次(在循环之前),因此基于其值的逻辑没有意义
  • 要从 arrayList 中删除使用迭代器
  • 为什么不直接使用removeAll
  • 对我来说听起来像是设置交叉点

标签: java arraylist


【解决方案1】:

更新

我认为你的问题最清楚的陈述是在你的一个 cmets 中:

是的,示例“示例:[dog,cat,cat,bird] 匹配 包含 [cat,dog] 为假,但包含 [cat,cat,dog] 为真?” 这正是我想要实现的目标。

所以说真的,你不是在寻找“子集”,因为它们不是集合。它们可以包含重复的元素。你真正想说的是你想看看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;
    }

如果您愿意,我可以使用 Java 泛型重写此代码以处理任意类型,而不仅仅是 Integer 对象。此外,所有代码都可以使用 Java 8 流(我最初使用的 - 请参阅下面的 cmets)来缩短。请在 cmets 中告诉我。

【讨论】:

  • @sparc-spread 当我们使用 java 7,6 时呢?顺便说一句,也许他应该从最简单的事情开始???
【解决方案2】:

如果您想从列表中删除元素,您有 2 个选择:

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

另见:

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

顺便说一句,为什么你不覆盖包含方法??

这里你使用像“Integer”这样的简单对象,你什么时候使用 List??

使用迭代器移除副本的示例:

    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

也不要使用 == 运算符来比较对象:) 而是使用 equal 方法

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

请记住,许多实现列表接口的类不会覆盖列表接口中的所有方法 - 因此您最终可能会遇到不受支持的操作异常 - 因此在这种情况下我更喜欢“低级”二进制/线性/混合搜索。

为了比较复杂的类对象,你需要重写 equal 和 hashCode 方法

如果您想删除重复值,只需将 arraylist(s) 放入 HashSet。它将根据您的对象的 equals() 删除重复项。 - 奥尔加

在 Java 中,HashMap 通过使用 hashCode 来定位存储桶。每个存储桶是驻留在该存储桶中的项目的列表。扫描项目,使用等号进行比较。添加项目时,一旦达到一定的负载百分比,就会调整 HashMap 的大小。

因此,有时它必须与几个项目进行比较,但通常它更接近 O(1) 而不是 O(n)。

简而言之 - 无需使用更多资源(内存)和“利用”不必要的类 - 因为哈希映射“get”方法会随着项目数量的增加而变得非常昂贵。

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

  so  what counts in removing items ? 

equals 和 hasCode 的复杂性以及使用适当的算法进行迭代

【讨论】:

    【解决方案3】:

    我知道这可能有点儿不成熟,但是......

    不需要从两个列表中删除项目,因此,只需从一个列表中取出它即可

    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;
    }
    

    【讨论】:

      【解决方案4】:

      如果要删除重复值,只需将 arraylist(s) 放入 HashSet。它将根据对象的 equals() 删除重复项。

      【讨论】:

        猜你喜欢
        • 2018-03-08
        • 2010-10-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-27
        • 1970-01-01
        • 2015-09-03
        相关资源
        最近更新 更多