简体   繁体   English

是否可以在排序中更改某些符号的优先级(权重)?

[英]Is it possible to change priority(weight) of certain symbols in sorting?

I want to create a comparator for string values, but according to https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html underscore symbol has bigger value than any digit.我想为字符串值创建一个比较器,但根据https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html下划线符号比任何数字都具有更大的价值。 Is it possible to change it somehow?有可能以某种方式改变它吗?

Short answer简答

Yes, it is.是的。 You need a custom string comparator.您需要一个自定义字符串比较器。

Solution解决方案

Let's say you need to sort a list of strings:假设您需要对字符串列表进行排序:

[a_123, ab123, a123, 123, _123]

If you sort it using Collections.sort then it'll be sorter in the following order:如果您使用Collections.sort对其进行排序,那么它将按以下顺序进行排序:

[123, _123, a123, a_123, ab123]

But you want to override the "weight" of _ .但是您想覆盖_的“权重”。 To achieve this you need a custom string comparator.为此,您需要一个自定义字符串比较器。 Let's copy and modify a bit java.lang.String#compareTo :让我们复制并修改一下java.lang.String#compareTo

private int customStringComparator(String s1, String s2) {
    int len1 = s1.length();
    int len2 = s2.length();
    int lim = Math.min(len1, len2);
    char v1[] = s1.toCharArray();
    char v2[] = s2.toCharArray();

    int k = 0;
    while (k < lim) {
        char c1 = v1[k];
        char c2 = v2[k];
        // You can add your custom comparison here:
        if ('_' == c1 && Character.isDigit(c2)) {
            // We intentionally return inverted result
            return c2  - c1;
        }else if(c1 != c2) {
            return c1 - c2;
        }
        k++;
    }
    return len1 - len2;
}

Now we can pass our customStringComparator to Collections.sort :现在我们可以将customStringComparator传递给Collections.sort

Collections.sort(list, this::customStringComparator);

The list will be sorted in the following order:该列表将按以下顺序排序:

[_123, 123, a_123, a123, ab123]

As you can see, now the _ precedes digits.如您所见,现在_在数字之前。

This might work:这可能有效:

private int compareStrings(String o1, String o2) {
    if(o1.matches("\\d+") && o2.equals("_")) {
        return 1;
    }
    if(o1.equals("_") && o2.matches("\\d+")) {
        return -1;
    }
    return o1.compareTo(o2);
}

And then define your comparator like so:然后像这样定义你的比较器:

Comparator<String> stringComparator2 = this::compareStrings;

EDIT:编辑:

According to not working for string with _ in the middle, how about just replacing _ with character that is before in ASCII table just for comparing (like " " for example):根据不为中间带有_字符串工作,如何将_替换为 ASCII 表中之前的字符以进行比较(例如" " ):

public static int compareStrings(String o1, String o2) {
    o1 = o1.replaceAll("_", " ");
    o2 = o2.replaceAll("_", " ");
    return o1.compareTo(o2);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM