Sure:
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()
, который делает одну копию массива и поэтому много быстрее
- вместо того, чтобы перестроить полученные строки из
StringBuilder
, я использовал an appropriate String
constructor, который, опять же, делает только один arraycopy
- (не требуется для производительности, но все же) Я изменил подпись метода на
length
в качестве параметра для моих целей тестирования. Не стесняйтесь менять его обратно - просто убедитесь, что вы переименовали метод от ngrams()
до ngrams12()
или что-то в этом роде.
Или бросьте все, в целом, и использовать наивное подход с 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;
}
Кстати, если вы когда-либо приходилось использовать regexp в будущем, попробуйте выполнить его компиляцию один раз и повторно использовать его, а не компилировать его каждый раз, когда метод будет использоваться. Например, ваш код будет выглядеть следующим образом:
private static final Pattern EVERY_CHAR = Pattern.compile("(?!^)");
, а затем, в способе, вместо String#split
, вы бы использовать
String[] parts = EVERY_CHAR.split(str);
Если у вас есть огромное количество входных строк с достаточной вероятностью повторения входных строк, тогда вы можете захотеть рассмотреть мемуацию этого метода, так как вывод зависит только от ввода. – Dancrumb