在List.contains(String)的情况下部分匹配字符串

时间:2011-07-11 03:05:12

标签: java regex

我有List<String>

List<String> list = new ArrayList<String>();
list.add("ABCD");
list.add("EFGH");
list.add("IJ KL");
list.add("M NOP");
list.add("UVW X");

如果我list.contains("EFGH"),则返回true。 如果list.contains("IJ"),我可以得到真的吗?我的意思是,我可以部分匹配字符串以查找它们是否存在于列表中吗?

我有15000个字符串的列表。如果它们存在于列表中,我必须检查大约10000个字符串。还有什么其他(更快)的方法可以做到这一点?

感谢。

9 个答案:

答案 0 :(得分:5)

如果Roadrunner-EX的建议不够,我相信您正在寻找Knuth–Morris–Pratt algorithm

时间复杂度:

  • 表算法的时间复杂度为O(n),预处理时间
  • 搜索算法的时间复杂度为O(k)

因此,整体算法的复杂性为O(n + k)。

  • n =列表的大小
  • k =您要搜索的模式的长度

正常蛮力的时间复杂度为O(nm)

此外,KMP算法对于使用相同的搜索字符串进行搜索将采用相同的O(k)复杂度,另一方面,对于强力接近,它将始终为O(km)。

答案 1 :(得分:4)

也许您想将每个String组放入一个HashSet,而且通过片段,我的意思是不添加“IJ KL”,而是分别添加“IJ”和“KL”。如果您同时需要列表和此搜索功能,则可能需要维护两个集合。

答案 2 :(得分:4)

作为第二个答案,在重新阅读您的问题时,您还可以继承接口List,仅将其专门用于Strings,并覆盖contains()方法。

public class PartialStringList extends ArrayList<String>
{
    public boolean contains(Object o)
    {
        if(!(o instanceof String))
        {
            return false;
        }
        String s = (String)o;
        Iterator<String> iter = iterator();
        while(iter.hasNext())
        {
            String iStr = iter.next();
            if (iStr.contain(s))
            {
                return true;
            }
        }
        return false;
    }
}

根据您之前的评论判断,这可能不是您所寻求的速度,但这更符合您的要求吗?

答案 3 :(得分:2)

您可以使用IterableUtils中的Apache Commons Collections

List<String> list = new ArrayList<String>();
list.add("ABCD");
list.add("EFGH");
list.add("IJ KL");
list.add("M NOP");
list.add("UVW X");

boolean hasString = IterableUtils.contains(list, "IJ", new Equator<String>() {
    @Override
    public boolean equate(String o1, String o2) {
        return o2.contains(o1);
    }

    @Override
    public int hash(String o) {
        return o.hashCode();
    }
});

System.out.println(hasString); // true

答案 4 :(得分:0)

您可以迭代列表,然后在每个String上调用contains()。

public boolean listContainsString(List<string> list. String checkStr)
{
    Iterator<String> iter = list.iterator();
    while(iter.hasNext())
    {
        String s = iter.next();
        if (s.contain(checkStr))
        {
            return true;
        }
    }
    return false;
}

我想这样的事情应该有用。

答案 5 :(得分:0)

怎么样:

java.util.List<String> list = new java.util.ArrayList<String>();
list.add("ABCD");
list.add("EFGH");
list.add("IJ KL");
list.add("M NOP");
list.add("UVW X");
java.util.regex.Pattern p = java.util.regex.Pattern.compile("IJ");
java.util.regex.Matcher m = p.matcher("");
for(String s : list)
{
    m.reset(s);
    if(m.find()) System.out.println("Partially Matched");
}

答案 6 :(得分:0)

如果在目标字符串中找到测试字符串的 none ,则会使用正则表达式来快速执行内部循环。

public static void main(String[] args) throws Exception {
    List<String> haystack = Arrays.asList(new String[] { "ABCD", "EFGH", "IJ KL", "M NOP", "UVW X" });
    List<String> needles = Arrays.asList(new String[] { "IJ", "NOP" });

    // To cut down on iterations, create one big regex to check the whole haystack
    StringBuilder sb = new StringBuilder();
    sb.append(".*(");
    for (String needle : needles) {
        sb.append(needle).append('|');
    }
    sb.replace(sb.length() - 1, sb.length(), ").*");
    String regex = sb.toString();

    for (String target : haystack) {
        if (!target.matches(regex)) {
            System.out.println("Skipping " + target);
            continue;
        }

        for (String needle : needles) {
            if (target.contains(needle)) {
                System.out.println(target + " contains " + needle);
            }
        }
    }
}

输出:

Skipping ABCD
Skipping EFGH
IJ KL contains IJ
M NOP contains NOP
Skipping UVW X

如果你真的想变得可爱,你可以使用二分搜索来识别目标列表的哪些段匹配,但它可能不值得。

这取决于你发现命中的可能性。低命中率将带来良好的结果。高命中率将比简单的嵌套循环版本好很多。如果某些针击中许多目标,则考虑反转循环,而其他针没有击中。

所有关于尽快中止搜索路径。

答案 7 :(得分:0)

是的,你可以!排序。

您正在寻找的内容通常称为fuzzy searching or approximate string matching,此问题有多种解决方案。

例如,使用FuzzyWuzzy lib,您可以根据与特定搜索字词的相似程度为所有字符串分配分数。实际值似乎是与搜索字符串长度匹配的字符数的整数百分比。

在调用FuzzySearch.extractAll之后,您可以决定将字符串视为匹配的最低分数。

还有其他类似的图书馆值得一试,例如google-diff-match-patchApache Commons Text Similarity API,等等。

如果你需要一些非常重的东西,最好的选择可能是LuceneRyan Shillington也提到)

答案 8 :(得分:0)

这不是对给定问题的直接答案。但是我想这个答案将帮助某人使用Apache Commons Collections来部分比较给定和列表中的元素。

final Equator equator = new Equator<String>() {
        @Override
        public boolean equate(String o1, String o2) {
            final int i1 = o1.lastIndexOf(":");
            final int i2 = o2.lastIndexOf(":");
            return o1.substring(0, i1).equals(o2.substring(0, i2));
        }

        @Override
        public int hash(String o) {
            final int i1 = o.lastIndexOf(":");
            return o.substring(0, i1).hashCode();
        }
    };
    final List<String> list = Lists.newArrayList("a1:v1", "a2:v2");
    System.out.println(IteratorUtils.matchesAny(list.iterator(), new EqualPredicate("a2:v1", equator)));