2

我知道这个名字有很多线程。我有一个生成 ngram 的代码。但是想知道在处理数千个字符串时是否可以改进以提高速度?

示例字符串="abcdefghijkl1245ty789"

public static String[] ngrams(String s) {
        int len=12;
        String[] parts = s.split("(?!^)");
        String[] result = new String[parts.length - len + 1];
        for(int i = 0; i < parts.length - len + 1; i++) {
           StringBuilder sb = new StringBuilder();
           for(int k = 0; k < len; k++) {
               sb.append(parts[i+k]);
           }
           result[i] = sb.toString();
        }
        return result;
    }

上面的代码得到一个字符串,生成给定长度的ngrmas。就我而言,它是 12。

4

1 回答 1

6

当然:

public static String[] ngrams(String str, int length) {
    char[] chars = str.toCharArray();
    final int resultCount = chars.length - length + 1;
    String[] result = new String[resultCount];
    for (int i = 0; i < resultCount; i++) {
        result[i] = new String(chars, i, length);
    }
    return result;
}

我所做的更改:

  • 我没有通过正则表达式进行拆分,而是使用String#toCharArray()了它进行单个数组复制,因此速度更快
  • 我没有从 a 重建生成的字符串StringBuilder,而是使用了一个适当的String构造函数,它再次只执行一个 arraycopy
  • (性能不需要,但仍然)我将方法签名更改为length作为测试原因的参数。随意将其改回 - 只需确保将方法重命名为ngrams()tongrams12()或其他名称。

或者完全放弃它并使用String#substring()的幼稚方法,在后台执行类似的工作:

public static String[] ngramsSubstring(String str, int length) {
    final int resultCount = str.length() - length + 1;
    String[] result = new String[resultCount];
    for (int i = 0; i < resultCount; i++) {
        result[i] = str.substring(i, i+length);
    }
    return result;
}

顺便说一句,如果您将来必须使用正则表达式,请尝试编译一次并重用它,而不是每次使用该方法时都编译它。例如,您的代码如下所示:

private static final Pattern EVERY_CHAR = Pattern.compile("(?!^)");

然后,在方法中String#split,您将使用

String[] parts = EVERY_CHAR.split(str);
于 2013-07-11T13:22:36.593 回答