【问题标题】:Using multiple Comparator to sort List of Strings multiple times使用多个比较器对字符串列表进行多次排序
【发布时间】:2015-02-05 08:49:48
【问题描述】:

我一直在尝试对字符串进行分组,忽略列表中存在的案例,并尝试以区分大小写的方式再次对它们进行排序。

所以,如果我有如下输入:

"Abc","DEF","abc","dEf"

那么我的输出应该被排序两次,因为使用 Comparator 的第一级排序应该是:

"Abc","abc","DEF","dEf"

第二级排序应该是:

"abc","Abc","dEf","DEF"

我的代码如下,它只包含一个比较器。我们可以使用多个比较器来实现这样的排序,或者调整单个比较器来实现这样的逻辑吗?

public class ListSortIgnoreCaseComparator {

    /**
     * @param args
     */
    public static void main(String[] args) {
        List<String> input = new ArrayList<>();
        input.add("Abc");
        input.add("DEF");
        input.add("abc");       
        input.add("dEf");
        System.out.println("Input: "+input);

        Collections.sort(input, new GroupIgnoreCase());
        System.out.println("Output: "+input);
    }
}

/**
 * 
 * @author 
 *
 */
class GroupIgnoreCase implements Comparator<String> {

    @Override
    public int compare(String s1, String s2) {      
        return s1.compareToIgnoreCase(s2);
    }

}
/**
 * 
 * @author 
 *
 */
class SortIgnoreCase implements Comparator<String> {

    @Override
    public int compare(String s3, String s4) {
        if(s3.equalsIgnoreCase(s4)){
            return s3.compareTo(s4);
        }
        return 0;
    }
}

输出如下:

Input: [Abc, DEF, abc, dEf]
Output: [Abc, abc, DEF, dEf]

我们可以调整比较器,使输出为:

Output: [abc, Abc, dEf, DEF]

而不是上面?

【问题讨论】:

  • 你试过用Collator代替吗?
  • @assylias a Collator 确实很强大,但如果没有你想要的,那就自己写吧,呃
  • @fge 我认为你不需要写一个 - 参见下面的答案。

标签: java sorting collections comparator


【解决方案1】:

是的,你可以忽略大小写比较它们,只有当它们相等时,你才应该再次比较它们,这次不要忽略大小写:

@Override
public int compare(String s1, String s2) {      
    int cmp = s1.compareToIgnoreCase(s2);
    if (cmp == 0)
        cmp = s1.compareTo(s2);
    return cmp;
}

【讨论】:

  • 怎么可能?你的compare() 方法仍然返回输出Output: [Abc, abc, DEF, dEf]。请仔细检查。
  • @Antony 好吧,我的回答展示了如何根据不区分大小写的比较“打破平局”。在区分大小写的字典顺序中,小写字母排在大写字母之后。如果要求小写字母排在大写字母之前,则相反的顺序可以解决问题 - s2.compareTo(s1)
【解决方案2】:

使用Collator 和强度TERTIARY

public class ListSortIgnoreCaseComparator {

    /**
     * @param args
     */
    public static void main(String[] args) {
        List<String> input = new ArrayList<>();
        input.add("Abc");
        input.add("DEF");
        input.add("abc");       
        input.add("dEf");
        System.out.println("Input: "+input);

        Collator c = Collator.getInstance();
        c.setStrength(Collator.TERTIARY);

        Collections.sort(input, c);
        System.out.println("Output: "+input);
    }
}

延伸阅读:Comparing Strings (The Java™ Tutorials > Internationalization > Working with Text)

【讨论】:

    【解决方案3】:

    这是我的解决方案:

    @Override
    public int compare(String s1, String s2) {
        int comVal = s1.compareToIgnoreCase(s2);
        if (comVal == 0) {
            return s2.compareTo(s1);
        } else {
            return comVal;
        }
    }
    
    Input: [Abc, DEF, abc, dEf]
    Output: [abc, Abc, dEf, DEF]
    

    【讨论】:

      最近更新 更多