我有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个字符串。还有什么其他(更快)的方法可以做到这一点?
感谢。
答案 0 :(得分:5)
如果Roadrunner-EX的建议不够,我相信您正在寻找Knuth–Morris–Pratt algorithm。
时间复杂度:
因此,整体算法的复杂性为O(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-patch或Apache Commons Text Similarity API,等等。
如果你需要一些非常重的东西,最好的选择可能是Lucene(Ryan 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)));