我有一个字符串:
1,2,3:3,4,5
分隔符左侧的字符串需要与分隔符右侧的字符串(:
)进行比较。现在,当我的意思是比较时,我实际上是要找出右侧部分(3,4,5)
中的元素是否存在于左侧部分(1,2,3)
的元素中。正确的部分可以包含重复项,这很好(显然我不能使用HashSet
)。我已经完成了这个(详情如下),但我需要以最快的方式来分割和比较上面提到的字符串。
这纯粹是一个基于性能的问题,以找出哪个方法可以更快,因为我将使用的实际输入是巨大的(在任何一方)。只有一行,它将通过 stdin 读取。
我是如何做到这一点的:
HashSet
。ArrayList
。contains()
遍历数组列表,检查HashSet
中是否存在该元素。答案 0 :(得分:2)
将输入读入byte[]
数组,以将指针放在代码的一侧。
逐字节读取,在路上计算整数元素:
int b = inputBytes[p++];
int d = b - '0';
if (0 <= d) {
if (d <= 9) {
element = element * 10 + d;
} else {
// b == ':'
}
} else {
// b == ','
// add element to the hash; element = 0;
...
}
if (p == inputBytesLength) {
inputBytesLength = in.read(inputBytes);
if (inputBytesLength == 0) { ... }
p = 0;
}
使用长度为2的足够大的int[]
作为哈希:
// as add()
int h = element * 0x9E3779B9;
int i = h >>> (32 - hashSizePower);
while (hash[i] != 0) {
if (--i < 0) i += hashSize;
}
hash[i] = element;
// contains() similarly
答案 1 :(得分:2)
假设一行输入符合JVM堆,那么从Java中的输入解析字符串的三种常用方法是:
java.util.Scanner
java.io.BufferedReader#readLine
&amp; java.util.StringTokenizer
java.io.BufferedReader#readLine
&amp; java.lang.String#split
对我而言,哪种方法最适合这个问题并不明显,所以我决定尝试一下。我生成了测试数据,为每种方法实现了解析器,并对结果进行了定时。
我生成了4个测试数据文件:
我生成的文件与您描述的格式相匹配。每个,
分隔元素都是一个随机整数。如果:
,文件名中的数字描述了每一侧的元素数量。例如,testdata_1k.txt左侧有1,000个元素,右侧有1,000个元素。
这是我用来测试每种方法的代码。请注意,这些不是生产质量代码的示例。
public Map<String, Boolean> scanner(InputStream stream) {
final Scanner in = new Scanner(new BufferedInputStream(stream));
final HashMap<String, Boolean> result = new HashMap<String, Boolean>();
final HashSet<String> left = new HashSet<String>();
in.useDelimiter(",");
boolean leftSide = true;
while (in.hasNext()) {
String token = in.next();
if (leftSide) {
int delim = token.indexOf(':');
if (delim >= 0) {
left.add(token.substring(0, delim));
String rightToken = token.substring(delim + 1, token.length());
result.put(rightToken, left.contains(rightToken));
leftSide = false;
} else {
left.add(token);
}
} else {
result.put(token, left.contains(token));
}
}
return result;
}
public Map<String, Boolean> stringTokenizer(InputStream stream) throws IOException {
final BufferedReader in = new BufferedReader(new InputStreamReader(stream));
final HashMap<String, Boolean> result = new HashMap<String, Boolean>();
final StringTokenizer lineTokens = new StringTokenizer(in.readLine(), ":");
final HashSet<String> left = new HashSet<String>();
if (lineTokens.hasMoreTokens()) {
final StringTokenizer leftTokens = new StringTokenizer(lineTokens.nextToken(), ",");
while (leftTokens.hasMoreTokens()) {
left.add(leftTokens.nextToken());
}
}
if (lineTokens.hasMoreTokens()) {
final StringTokenizer rightTokens = new StringTokenizer(lineTokens.nextToken(), ",");
while (rightTokens.hasMoreTokens()) {
String token = rightTokens.nextToken();
result.put(token, left.contains(token));
}
}
return result;
}
public Map<String, Boolean> split(InputStream stream) throws IOException {
final BufferedReader in = new BufferedReader(new InputStreamReader(stream));
final HashMap<String, Boolean> result = new HashMap<String, Boolean>();
final String[] splitLine = in.readLine().split(":");
final HashSet<String> left = new HashSet<String>(Arrays.asList(splitLine[0].split(",")));
for (String element : splitLine[1].split(",")) {
result.put(element, left.contains(element));
}
return result;
}
我针对每个文件运行了6次。我扔掉了第一个样品。以下代表剩余5个样本的平均值。
假设您的数据适合JVM堆,与String.split
和StringTokenizer
相比,很难超过Scanner
的解析速度。