查找以给定前缀

时间:2017-05-24 15:29:42

标签: java treeset

我正在尝试在TreeSet<String>中找到以给定前缀开头的字符串。我发现前一个问题要求同样的事情 - Searching for a record in a TreeSet on the fly - 但那里给出的答案对我不起作用,因为它假定字符串不包括Character.MAX_VALUE,而我的可以。< / p>

(答案是使用treeSet.subSet(prefix, prefix + Character.MAX_VALUE),它提供prefix(包含)和prefix + Character.MAX_VALUE(不包括)之间的所有字符串,这些字符串以{{{ 1}} 除了prefix开头的那些。但在我的情况下,我需要找到以prefix + Character.MAX_VALUE开头的所有字符串,包括prefix开头的那些。)

我该怎么做?

2 个答案:

答案 0 :(得分:0)

首先,我建议您重新检查一下您的要求。 Character.MAX_VALUE是U + FFFF,它不是有效的Unicode字符,永远不会是;所以我无法想出你需要支持它的一个很好的理由。

但如果这个要求有充分的理由,那么 - 你需要增加&#34;你的前缀用于计算最少的字符串,该字符串大于以前缀开头的所有字符串。例如,给定"city",您需要"citz"。你可以这样做:

/**
 * @param prefix
 * @return The least string that's greater than all strings starting with
 *         prefix, if one exists. Otherwise, returns Optional.empty().
 *         (Specifically, returns Optional.empty() if the prefix is the
 *         empty string, or is just a sequence of Character.MAX_VALUE-s.)
 */
private static Optional<String> incrementPrefix(final String prefix) {
    final StringBuilder sb = new StringBuilder(prefix);

    // remove any trailing occurrences of Character.MAX_VALUE:
    while (sb.length() > 0 && sb.charAt(sb.length() - 1) == Character.MAX_VALUE) {
        sb.setLength(sb.length() - 1);
    }

    // if the prefix is empty, then there's no upper bound:
    if (sb.length() == 0) {
        return Optional.empty();
    }

    // otherwise, increment the last character and return the result:
    sb.setCharAt(sb.length() - 1, (char) (sb.charAt(sb.length() - 1) + 1));
    return Optional.of(sb.toString());
}

要使用它,您需要在上述方法返回字符串时使用subSet,并在不返回任何内容时使用tailSet

/**
 * @param allElements - a SortedSet of strings. This set must use the
 *                      natural string ordering; otherwise this method
 *                      may not behave as intended.
 * @param prefix
 * @return The subset of allElements containing the strings that start
 *         with prefix.
 */
private static SortedSet<String> getElementsWithPrefix(
        final SortedSet<String> allElements, final String prefix) {

    final Optional<String> endpoint = incrementPrefix(prefix);

    if (endpoint.isPresent()) {
        return allElements.subSet(prefix, endpoint.get());
    } else {
        return allElements.tailSet(prefix);
    }
}

请参阅:http://ideone.com/YvO4b3

答案 1 :(得分:0)

如果有人正在寻找ruakh答案的简短版本:

第一个元素实际上是set.ceiling(prefix),最后一个-您必须增加前缀并使用set.floor(next_prefix)

public NavigableSet<String> subSetWithPrefix(NavigableSet<String> set, String prefix) {
    String first = set.ceiling(prefix);
    char[] chars = prefix.toCharArray();
    if(chars.length>0)
        chars[chars.length-1] = (char) (chars[chars.length-1]+1);
    String last = set.floor(new String(chars));
    if(first==null || last==null || last.compareTo(first)<0)
        return new TreeSet<>();
    return set.subSet(first, true, last, true);
}