Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 字符串拆分和比较-最快的方法_Java_String_Performance_Split - Fatal编程技术网

Java 字符串拆分和比较-最快的方法

Java 字符串拆分和比较-最快的方法,java,string,performance,split,Java,String,Performance,Split,我有一个字符串,比如: 1,2,3:3,4,5 需要将分隔符左侧的字符串与分隔符右侧的字符串进行比较(:)。现在,当我的意思是比较时,我实际上是想找出右部分(3,4,5)中的元素是否存在于左部分(1,2,3)中。右边的部分可以包含重复项,这很好(显然意味着我不能使用哈希集)。我已经完成了这项工作(细节如下),但我需要最快的方法来分割和比较上述字符串 这纯粹是一个基于性能的问题,旨在找出哪种方法更快,因为我将使用的实际输入是巨大的(在任何一边)。只有一行,将通过stdin读取 我是如何做到这一点的

我有一个字符串,比如:

1,2,3:3,4,5

需要将分隔符左侧的字符串与分隔符右侧的字符串进行比较(
)。现在,当我的意思是比较时,我实际上是想找出右部分
(3,4,5)
中的元素是否存在于左部分
(1,2,3)
中。右边的部分可以包含重复项,这很好(显然意味着我不能使用
哈希集)。我已经完成了这项工作(细节如下),但我需要最快的方法来分割和比较上述字符串

这纯粹是一个基于性能的问题,旨在找出哪种方法更快,因为我将使用的实际输入是巨大的(在任何一边)。只有一行,将通过stdin读取

我是如何做到这一点的:

  • 阅读标准文本
  • 使用string.Split进行拆分,并将左侧部分存储在
    哈希集中
  • 将正确的部分存储在
    阵列列表中
  • 遍历数组列表,使用
    contains()
    检查
    哈希集中是否存在元素
  • 将输入读入
    字节[]
    数组,将指针固定在代码的一侧

  • 逐字节读取,同时计算整数元素:

    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;
    }
    

  • 假设JVM堆中有一行输入,在Java中解析输入字符串的三种常用方法是:

  • java.util.Scanner
  • java.io.BufferedReader#readLine
    java.util.StringTokenizer
  • java.io.BufferedReader#readLine
    java.lang.String#split
  • 我不清楚哪种方法最适合解决这个问题,所以我决定尝试一下。我生成了测试数据,为每种方法实现了一个解析器,并对结果计时

    测试数据 我生成了4个测试数据文件:

    • testdata_1k.txt-大小为20KB
    • testdata_10k.txt-大小为205KB
    • testdata_100k.txt-大小为2MB
    • testdata_1000k.txt-尺寸为20M
    我生成的文件与您描述的格式匹配。每个
    分隔的元素都是一个随机整数。如果
    ,则文件名中的数字描述每侧的元素数量。例如,testdata_1k.txt左侧有1000个元素,右侧有1000个元素

    测试代码 下面是我用来测试每种方法的代码。请注意,这些不是生产质量代码的示例

    扫描代码
    公共地图扫描仪(InputStream){
    最终扫描仪输入=新扫描仪(新的BufferedInputStream(stream));
    最终HashMap结果=新HashMap();
    final HashSet left=新HashSet();
    in.useDelimiter(“,”);
    布尔值leftSide=true;
    while(在.hasNext()中){
    字符串标记=in.next();
    如果(左侧){
    int delim=token.indexOf(':');
    如果(delim>=0){
    左.add(token.substring(0,delim));
    String rightToken=token.substring(delim+1,token.length());
    put(rightToken,left.contains(rightToken));
    leftSide=false;
    }否则{
    左。添加(令牌);
    }
    }否则{
    put(token,left.contains(token));
    }
    }
    返回结果;
    }
    
    字符串标记器代码
    公共映射stringTokenizer(InputStream流)引发IOException{
    final BufferedReader in=新的BufferedReader(新的InputStreamReader(流));
    最终HashMap结果=新HashMap();
    final StringTokenizer lineTokens=新的StringTokenizer(in.readLine(),“:”);
    final HashSet left=新HashSet();
    if(lineTokens.hasMoreTokens()){
    final StringTokenizer leftTokens=新的StringTokenizer(lineTokens.nextToken(),“,”);
    while(leftTokens.hasMoreTokens()){
    添加(leftTokens.nextToken());
    }
    }
    if(lineTokens.hasMoreTokens()){
    final StringTokenizer rightTokens=新的StringTokenizer(lineTokens.nextToken(),“,”);
    while(rightokens.hasMoreTokens()){
    String token=rightTokens.nextToken();
    put(token,left.contains(token));
    }
    }
    返回结果;
    }
    
    String.split代码
    公共映射拆分(InputStream流)引发IOException{
    final BufferedReader in=新的BufferedReader(新的InputStreamReader(流));
    最终HashMap结果=新HashMap();
    最后一个字符串[]splitLine=in.readLine().split(“:”);
    final HashSet left=新的HashSet(Arrays.asList(splitLine[0].split(“,”));
    对于(字符串元素:拆分行[1]。拆分(“,”){
    put(元素,左。包含(元素));
    }
    返回结果;
    }
    
    时机 我针对每个文件运行了每种方法6次。我扔掉了第一个样品。以下为剩余5个样本的平均值

    扫描仪
    • testdata_1k.txt-23.2948毫秒
    • testdata_10k.txt-39.5036毫秒
    • testdata_100k.txt-240.5626毫秒
    • testdata_1000k.txt-2671.5132毫秒
    字符串标记器
    • testdata_1k.txt-31.2344毫秒
    • testdata_10k.txt-14.7926毫秒
    • testdata_100k.txt-102.6412毫秒
    • testdata_1000k.txt-1353.073毫秒
    String.split
    • testdata_1k.txt-8.9596毫秒
    • testdata_10k.txt-7.8396毫秒
    • testdata_100k.txt-63.4854毫秒
    • testdata_1000k.txt-947.8384毫秒
    结论
    假设您的数据适合JVM堆,与
    StringTokenizer
    Scanner
    相比,很难超过
    String.split
    的解析速度

    关于重复,您在RHS上所说的HashSet
    对我来说毫无意义。IIUYC重复项无论如何都会被忽略,因为你不知道发生了多少次。数字能有多大?好的,所以它没有意义的原因是因为我不能忽略
    // 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
    
    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;
    }