【问题标题】:How to compare two huge List<String> in Java?如何在 Java 中比较两个巨大的 List<String>?
【发布时间】:2017-01-18 15:17:47
【问题描述】:

我的应用程序生成 2 个大列表(最多 3.5mill 字符串记录)。我需要最好和最快的方法来比较它。目前我正在这样做:

List list1 = ListUtils.subtract(sourceDbResults, hiveResults);
List list2 = ListUtils.subtract(hiveResults, sourceDbResults);

但是正如我从 jconsole 中看到的那样,这种方法在内存上确实很昂贵,有时甚至会在其上处理堆栈。有什么好的解决方案或想法吗?

列表中的元素位置/顺序总是相同的,所以我不需要处理它。比较之后,我需要知道列表是否相同,如果它们不同,则需要从这些列表中获取差异。减法非常适合小型列表。

【问题讨论】:

  • 重新打开。看起来不像 stackoverflow.com/questions/41608074/… 的副本。在另一个问题中,列表的长度仅为 100,000,并且由于某些未知原因,问题是内存不足。这个问题似乎更多关于算法。
  • 您只需要知道这两个列表是否相等吗?元素的顺序重要吗?您是否需要任何其他信息,例如 list1 是否是 other 的子集。
  • 您能否通过比较两个列表来更好地描述您的意思?
  • 列表是否排序?
  • @KlitosKyriacou 是的,列表是排序器。我不需要解决这个问题

标签: java arraylist


【解决方案1】:

鉴于您已经说过您的两个列表已经排序,它们可以在 O(N) 时间内进行比较,这比您当前使用 ListUtils 的解决方案要快得多。以下方法使用与合并大多数教科书中可以找到的两个排序列表的算法类似的算法来执行此操作。

import java.util.*;

public class CompareSortedLists {
    public static void main(String[] args) {
        List<Integer> sourceDbResults = Arrays.asList(1, 2, 3, 4, 5, 8);
        List<Integer> hiveResults = Arrays.asList(2, 3, 6, 7);
        List<Integer> inSourceDb_notInHive = new ArrayList<>();
        List<Integer> inHive_notInSourceDb = new ArrayList<>();

        compareSortedLists(
                sourceDbResults, hiveResults,
                inSourceDb_notInHive, inHive_notInSourceDb);

        assert inSourceDb_notInHive.equals(Arrays.asList(1, 4, 5, 8));
        assert inHive_notInSourceDb.equals(Arrays.asList(6, 7));
    }

    /**
     * Compares two sorted lists (or other iterable collections in ascending order).
     * Adds to onlyInList1 any and all elements in list1 that are not in list2; and
     * conversely to onlyInList2. The caller must ensure the two input lists are
     * already sorted and should initialize onlyInList1 and onlyInList2 to empty,
     * writable collections.
     */
    public static <T extends Comparable<? super T>> void compareSortedLists(
            Iterable<T> list1, Iterable<T> list2,
            Collection<T> onlyInList1, Collection<T> onlyInList2) {
        Iterator<T> it1 = list1.iterator();
        Iterator<T> it2 = list2.iterator();
        T e1 = it1.hasNext() ? it1.next() : null;
        T e2 = it2.hasNext() ? it2.next() : null;
        while (e1 != null || e2 != null) {
            if (e2 == null) {  // No more elements in list2, some remaining in list1
                onlyInList1.add(e1);
                e1 = it1.hasNext() ? it1.next() : null;
            }
            else if (e1 == null) {  // No more elements in list1, some remaining in list2
                onlyInList2.add(e2);
                e2 = it2.hasNext() ? it2.next() : null;
            }
            else {
                int comp = e1.compareTo(e2);
                if (comp < 0) {
                    onlyInList1.add(e1);
                    e1 = it1.hasNext() ? it1.next() : null;
                }
                else if (comp > 0) {
                    onlyInList2.add(e2);
                    e2 = it2.hasNext() ? it2.next() : null;
                }
                else /* comp == 0 */ {
                    e1 = it1.hasNext() ? it1.next() : null;
                    e2 = it2.hasNext() ? it2.next() : null;
                }
            }
        }
    }
}

上述方法不使用外部库,可用于Java 6 以上的任何版本。如果您使用 PeekingIterator,例如来自 Apache Commons Collections 的 PeekingIterator 或 Guava,或者自己编写,那么您可以使方法更简单,特别是如果您还使用 Java 8:

public static <T extends Comparable<? super T>> void compareSortedLists(
        Iterable<T> list1, Iterable<T> list2,
        Collection<T> onlyInList1, Collection<T> onlyInList2) {
    PeekingIterator<T> it1 = new PeekingIterator<>(list1.iterator());
    PeekingIterator<T> it2 = new PeekingIterator<>(list2.iterator());
    while (it1.hasNext() && it2.hasNext()) {
        int comp = it1.peek().compareTo(it2.peek());
        if (comp < 0)
            onlyInList1.add(it1.next());
        else if (comp > 0)
            onlyInList2.add(it2.next());
        else /* comp == 0 */ {
            it1.next();
            it2.next();
        }
    }
    it1.forEachRemaining(onlyInList1::add);
    it2.forEachRemaining(onlyInList2::add);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-11
    • 2013-06-08
    • 2014-12-03
    • 2023-04-07
    • 1970-01-01
    相关资源
    最近更新 更多