【问题标题】:Looking up an element in a huge list在一个巨大的列表中查找一个元素
【发布时间】:2018-07-15 18:04:06
【问题描述】:

我有一个巨大的字符串列表 (List<String>),其中可能包含超过 10.000 个唯一元素(字符串),我需要参考这个列表多对多(可能超过 10.000 ,也是)在循环中确定列表是否包含某些元素。

例如:

/**
 * The size of this list might be over 10.000.
 */
public static final List<String> list = new ArrayList<>();

<...>
/**
 * The size of the 'x' list might be over 10.000, too.
 *
 * This method just does something with elements in the list 'x'
 * which are not in the list 'list' (for example (!), just returns them).
 */
public static List<String> findWhatsNotInList(List<String> x) {
    List<String> result = new ArrayList<>();

    for (String s : x) {
        if (list.contains(s))
            continue;
        result.add(s);
    }

    return result;
}
<...>

根据listx 列表的大小,此方法可能会执行几分钟,这太长了。

有没有办法加快这个过程? (在完全替换 List 并循环使用其他内容时,请随意提出任何内容。)

编辑:尽管使用了List#contains 方法,但我可能需要使用List#stream 并进行一些检查,而不仅仅是String#equals(例如使用startsWith)。例如:

/**
 * The size of this list might be over 10.000.
 */
public static final List<String> list = new ArrayList<>();

<...>
/**
 * The size of the 'x' list might be over 10.000, too.
 *
 * This method just does something with strings in the list 'x'
 * which do not start with any of strings in the list 'list' (for example (!), just returns them).
 */
public static List<String> findWhatsNotInList(List<String> x) {
    List<String> result = new ArrayList<>();

    for (String s : x) {
        if (startsWithAny(s, list))
            continue;
        result.add(s);
    }

    return result;
}
<...>
/**
 * Check if the given string `s` starts with anything from the list `list`
 */
public boolean startsWithAny(String s, List<String> sw) {
    return sw.stream().filter(s::startsWith).findAny().orElse(null) != null;
}
<...>

编辑#2:一个例子:

public class Test {

    private static final List<String> list = new ArrayList<>();

    static {
        for (int i = 0; i < 7; i++) {
            list.add(Integer.toString(i));
        }
    }

    public static void main(String[] args) {
        List<String> in = new ArrayList<>();

        for (int i = 0; i < 10; i++)
            in.add(Integer.toString(i));
        List<String> out = findWhatsNotInList(in);

        // Prints 7, 8 and 9 — Strings that do not start with
        // 0, 1, 2, 3, 4, 5, or 6 (Strings from the list `list`)
        out.forEach(System.out::println);
    }

    private static List<String> findWhatsNotInList(List<String> x) {
        List<String> result = new ArrayList<>();

        for (String s : x) {
            if (startsWithAny(s, list))
                continue;
            result.add(s);
        }

        return result;
    }

    private static boolean startsWithAny(String s, List<String> sw) {
        return sw.stream().filter(s::startsWith).findAny().orElse(null) != null;
    }

}

【问题讨论】:

  • 你考虑过List以外的其他数据结构吗?
  • 是否可以将“列表”设为集合而不是列表。列表中包含的方法需要 O(N) 才能运行,其中 Set 有 O(1)。
  • 编辑了帖子:我实际上需要通过列表list 进行流式传输并执行startsWith,而不仅仅是contains。我很抱歉。
  • 对于startsWith,您可以先订购您的数据。

标签: java list arraylist bigdata


【解决方案1】:

你基本上是在问如何最好地重新发明轮子。

唯一合理的答案是:不要。

含义:你想对“大数据”进行大规模搜索。我建议您转而研究 Solr 或 ElasticSearch 等框架。因为处理大量数据的唯一真正答案是过度使用“横向扩展”解决方案。做“你自己”是一项严肃的事业!

如果您的需求有可能会“增长”并且需要更复杂的搜索,那么请花费您的精力来选择最佳匹配技术。而不是尝试构建难以构建的东西。

上述框架会带来一定的开销 - 但如果使用得当,它们可以掌握 TB 级的数据。作为一个单一的开发者,你所能提出的任何事情都不会接近这一点。在你的路上,你很可能会重复每个人都犯的同样的错误。或者,如前所述,您选择了多年前发现此类错误并修复它们的工具。

【讨论】:

    猜你喜欢
    • 2019-03-25
    • 1970-01-01
    • 2023-03-22
    • 2021-06-20
    • 1970-01-01
    • 2011-08-17
    • 2018-07-28
    • 2017-04-28
    相关资源
    最近更新 更多