在标准Java库中,找出两个list是否包含完全相同的元素的最简单方法是什么?

这两个list是否为相同实例并不重要,这两个list的类型参数是否不同也不重要。

e.g.

List list1
List<String> list2; 
// ... construct etc

list1.add("A");
list2.add("A"); 
// the function, given these two lists, should return true

我知道可能有什么东西在盯着我的脸:-)


编辑:为了澄清,我正在寻找完全相同的元素和元素的数量,按顺序。


当前回答

我知道这可能非常晚,但我个人使用这个功能。 如果有人想做一些基准测试,那就太好了。

public static<X> boolean areEqual(List<X> a, List<X> b, BiPredicate<X, X> AEqualsB) {
        boolean aIsNull = a == null;
        boolean bIsNull = b == null;
        if (aIsNull || bIsNull) {
            return aIsNull == bIsNull;
        }
        int size = a.size();
        boolean sameSize = size == b.size();
        if (!sameSize) {return false;} else {
            for (int i = 0; i < size; i++) {
                X aX = a.get(i), bX = b.get(i);
                boolean areEqual = AEqualsB.test(aX, bX);
                if (!areEqual) {
                    return false;
                }
            }
            return true;
        }
    }

顺便说一句,我知道前5行可以用一个异或“^”加上一个else来简化,但信不信由你,我很难得出正确的异或。

我想它的效率取决于谓词的类型,但同时它允许您检查自定义的潜在相等,而忽略对编码器来说可能无关紧要的差异。

下面是一个代码示例。

ListUtils.areEqual(newElements, oldElements, Element::areEqual)

public boolean areEqual(Element e) {
        return optionalAdapterId() == e.optionalAdapterId()
                && value == e.value
                && valueTotal == e.valueTotal
                && stockTotal == e.stockTotal
                && element_title.equals(e.element_title);
    }

至于效率,我认为任何迭代总是昂贵,这就是为什么每当我需要使用这个函数与大名单,我在一个单独的线程执行的操作,和检索响应的需要,即使它很高兴知道此时,它是有益的在一个不同的线程,是什么项目,要求这些线程的数量,这些信息将被添加文档。

其他回答

当两个列表具有相同的元素,但顺序不同时的解决方案:

public boolean isDifferentLists(List<Integer> listOne, List<Integer> listTwo) {
    if(isNullLists(listOne, listTwo)) {
        return false;
    }

    if (hasDifferentSize(listOne, listTwo)) {
        return true;
    }

    List<Integer> listOneCopy = Lists.newArrayList(listOne);
    List<Integer> listTwoCopy = Lists.newArrayList(listTwo);
    listOneCopy.removeAll(listTwoCopy);

    return CollectionUtils.isNotEmpty(listOneCopy);
}

private boolean isNullLists(List<Integer> listOne, List<Integer> listTwo) {
    return listOne == null && listTwo == null;
}

private boolean hasDifferentSize(List<Integer> listOne, List<Integer> listTwo) {
    return (listOne == null && listTwo != null) || (listOne != null && listTwo == null) || (listOne.size() != listTwo.size());
}

我的解决方案适用于不关心列表中的顺序的情况——换句话说:具有相同元素但顺序不同的列表将被认为具有相同的内容。

示例:["word1", "word2"]和["word2", "word1"]被认为内容相同。

我已经谈到了订购,我还需要说一些关于副本的事情。列表需要具有相同数量的元素才能被认为是相等的。

例如:["word1"]和["word1", "word1"]被认为不具有相同的内容。

我的解决方案:

public class ListUtil {

    public static <T> boolean hasSameContents(List<T> firstList, List<T> secondList) {      
        if (firstList == secondList) { // same object
            return true;
        }
        if (firstList != null && secondList != null) {
            if (firstList.isEmpty() && secondList.isEmpty()) {
                return true;
            }
            if (firstList.size() != secondList.size()) {
                return false;
            }
            List<T> tmpSecondList = new ArrayList<>(secondList);
            Object currFirstObject = null;
            for (int i=1 ; i<=firstList.size() ; i++) {
                currFirstObject = firstList.get(i-1);
                boolean removed = tmpSecondList.remove(currFirstObject);
                if (!removed) {
                    return false;
                }
                if (i != firstList.size()) { // Not the last element
                    if (tmpSecondList.isEmpty()) {
                        return false;
                    }
                }
            }
            if (tmpSecondList.isEmpty()) {
                return true;
            }
        }
        return false;
    }
}

我用Strings进行了测试,如下所示:

@Test public void testHasSameContents() throws Exception { // comparing with same list => no duplicate elements Assert.isTrue(ListUtil.hasSameContents(List.of("one", "two", "three"), List.of("one", "two", "three"))); // comparing with same list => duplicate elements Assert.isTrue(ListUtil.hasSameContents(List.of("one", "two", "three", "one"), List.of("one", "two", "three", "one"))); // compare with disordered list => no duplicate elements Assert.isTrue(ListUtil.hasSameContents(List.of("one", "two", "three"), List.of("three", "two", "one"))); // compare with disordered list => duplicate elements Assert.isTrue(ListUtil.hasSameContents(List.of("one", "two", "three", "one"), List.of("three", "two", "one", "one"))); // comparing with different list => same size, no duplicate elements Assert.isFalse(ListUtil.hasSameContents(List.of("one", "two", "three"), List.of("four", "five", "six"))); // comparing with different list => same size, duplicate elements Assert.isFalse(ListUtil.hasSameContents(List.of("one", "two", "two"), List.of("one", "two", "three"))); Assert.isFalse(ListUtil.hasSameContents(List.of("one", "two", "three"), List.of("one", "two", "two"))); // comparing with different list => different size, no duplicate elements Assert.isFalse(ListUtil.hasSameContents(List.of("one", "two", "three", "four"), List.of("one", "two", "three"))); Assert.isFalse(ListUtil.hasSameContents(List.of("one", "two", "three"), List.of("one", "two", "three", "four"))); // comparing with different list => different sizes, duplicate elements Assert.isFalse(ListUtil.hasSameContents(List.of("one", "two", "three", "one"), List.of("one", "two", "three"))); Assert.isFalse(ListUtil.hasSameContents(List.of("one", "two", "three"), List.of("one", "two", "three", "one"))); }

如果您正在使用(或乐于使用)Apache Commons Collections,您可以使用CollectionUtils。isEqualCollection“如果给定集合包含完全相同的元素和完全相同的基数,则返回true。”

下面是一种比较两个集合的方法,它考虑了其中的重复。因此,集合大小不一定相同。因此,它会在'actual'中寻找'expected':

    private static <T> boolean containsAllExpected(Collection<T> actual, Collection<T> expected) {
        if (actual == null && expected == null) {
            return true;
        }
        if (actual == null || expected == null) {
            return false;
        }
        Collection<T> a = new ArrayList<>(actual);
        Collection<T> e = new ArrayList<>(expected);

        Iterator<T> ei = e.iterator();
        while (ei.hasNext()) {
            T item = ei.next();
            if (a.contains(item)) {
                ei.remove();
                a.remove(item);
            } else {
                return false;
            }
        }

        return true;
    }

享受:)

这应该在O(n)时间内完成。

public static <T> boolean isEqualCollection(Collection<T> c1, Collection<T> c2){
    if(nonNull(c1) && nonNull(c2)){
        Map<T, Long> c1Counts = c1.stream().collect(Collectors.groupingBy(i -> i, Collectors.counting()));
        for(T item : c2) {
            Long count  = c1Counts.getOrDefault(item, 0L);
            if(count.equals(0L)){
                return false;
            } else {
                c1Counts.put(item, count - 1L);
            }
        }
        return true;
    }
    return isNull(c1) && isNull(c2);
}