我在两个文件中有两组字符串不是很长(200~500字),如下所示:
File1 File2
this window
that good
word work
java fine
book home
所有独特的单词。
现在首先从文件中读取字符串(逐行)并将它们存储在:
中Set<String> set1 Set<String> set2
:可能如下所示:[this, that, word, java, book]
和 [window, good, work, fine, home]
或
String str1 String str2
:可能如下所示:str1: thisthatwordjava
和 str2: windowgoodworkfinehome
或可以是str1: this,that,word,java
(已分隔)用逗号表示。现在有三种方法可以检查home
或Set
将出现的单词String
:
set1/2.contains("home")
str1/2.contains("home")
str1/2.matches("home")
以上所有内容都可以正常使用,但 BEST 中的哪一个
注意:此问题的目的是因为检查字符串的频率非常高。
答案 0 :(得分:2)
是什么让你认为String.contains会有更好的表现&#34;?
除了非常简单的情况之外,它不会是:
对于所有其他情况,Set
方法将扩展并更好地工作。当然,您将拥有Set的内存开销而不是单个字符串,但即使您想存储数百万个字符串并比较长字符串,O(1)查找也将保持不变。
使用更安全,更健壮的设计,尤其是在这里,它并不是一个难以实施的解决方案。正如你提到的那样,你会经常检查,然后一套方法对你来说肯定更好。
此外,String.contain将是不安全的,就好像你们两个都有匹配的字符串和子字符串,你的查找将失败。正如kennytm在评论中所说,如果我们使用你的例子,你就得到了&#34; java&#34;列表中的字符串,查找&#34; ava&#34;会匹配它,你显然不想要它。
您可能不想使用简单的HashSet或调整其设置。例如,你可以考虑一个Guava ImmutableSet,如果你的集合只创建一次但经常检查。
这就是我要做的事情,假设你想要一个不可变的集合(就像你说你从文件中读取字符串列表一样)。这是副手,没有验证,所以原谅缺乏仪式。
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Files;
import com.google.common.base.Splitter;
final Set<String> lookupTable = ImmutableSet.copyOf(
Splitter.on(',')
.trimResults()
.omitEmptyStrings()
.split(Files.asCharSource(new File("YOUR_FILE_PATH"), Charsets.UTF_8).read())
);
如果您想要允许空格和空字符串,请使用正确的路径,正确的字符集以及修剪或不修剪的季节。
如果你不想使用Guava而只想使用vanilla Java,那么只需在Java 8中做这样的事情(再次,道歉,未经测试):
final Set<String> lookupTable =
Files.lines(Paths.get("YOUR_FILE_PATH"))
.map(line -> line.split(",+"))
.map(Arrays::stream)
.collect(toSet());
如果你有Java&lt; 8,然后使用通常的FileInputStream读取文件,然后使用String.split []或StringTokenizer提取数组,最后将数组条目添加到Set中。
答案 1 :(得分:0)
我猜你无论如何都要把文件的行读成一个字符串,所以如果你只计划一个查询,那么拆分它并将子字符串存储在一个集合中并不是最理想的。
答案 2 :(得分:0)
如果您想了解一些有关性能差异的信息。只需测量它。这是一个适合您的测试设置。
final int WORDS = 10000;
final int SEARCHES = 1000000;
Set<String> strSet = new TreeSet<String>();
String strStr = "";
int[] searches = new int[SEARCHES];
Random randomGenerator = new Random();
// filling set and string
for(int i = 0; i < WORDS; i++){
strSet.add(String.valueOf(i));
strStr += "," + String.valueOf(i);
}
// creating searches
for(int i = 0; i < SEARCHES; i++)
searches[i] = randomGenerator.nextInt(WORDS);
// measure set
long startTime = System.currentTimeMillis();
for(int i = 0; i < SEARCHES; i++)
strSet.contains(String.valueOf(searches[i]));
System.out.println("set result " + (System.currentTimeMillis() - startTime));
// measure string
startTime = System.currentTimeMillis();
for(int i = 0; i < SEARCHES; i++)
strStr.contains(String.valueOf(searches[i]));
System.out.println("string result " + (System.currentTimeMillis() - startTime));
对我来说,输出是一个有意义的证明,你应该留在Set
设定结果350
字符串结果14197
答案 3 :(得分:0)
如果给出没有逗号的单词,可以占用更多的内存空间,但执行时间更短(可以通过简单的拆分完成)
但我真正认为最好的方法是实验证明System.currentTimeMillis()