【问题标题】:How do I use Comparator to define a custom sort order?如何使用 Comparator 定义自定义排序顺序?
【发布时间】:2021-09-18 20:44:21
【问题描述】:

我想为汽车列表开发一个排序演示。我正在使用数据表来显示汽车列表。现在实际上我想按汽车颜色对列表进行排序。这里不是按字母顺序排序的。我想使用我的自定义排序顺序,比如先红车,然后是蓝车,等等。

为此,我尝试使用 Java ComparatorComparable,但它只允许按字母顺序排序。

那么,任何人都可以指导我实现使用该技术的方法,以便排序变得更快。

class Car implements Comparable<Car>
{
    private String name;
    private String color;

    public Car(String name, String color){
        this.name = name;
        this.color = color;
    }

    //Implement the natural order for this class
    public int compareTo(Car c) {
        return name.compareTo(c.name);
    }

    static class ColorComparator implements Comparator<Car> {
        public int compare(Car c1, Car c2) {
            String a1 = c1.color;
            String a2 = c2.color;
            return a1.compareTo(a2);
        }
    }

    public static void main(String[] args) {
        List<Car> carList = new ArrayList<>();
        List<String> sortOrder = new ArrayList<>();

        carList.add(new Car("Ford","Silver"));
        carList.add(new Car("Tes","Blue"));
        carList.add(new Car("Honda","Magenta"));

        sortOrder.add("Silver");
        sortOrder.add("Magenta");
        sortOrder.add("Blue");

        // Now here I am confuse how to implement my custom sort             
    }
}

【问题讨论】:

    标签: java sorting enums


    【解决方案1】:

    我建议您为汽车颜色创建一个枚举,而不是使用字符串,枚举的自然顺序将是您声明常量的顺序。

    public enum PaintColors {
        SILVER, BLUE, MAGENTA, RED
    }
    

     static class ColorComparator implements Comparator<CarSort>
     {
         public int compare(CarSort c1, CarSort c2)
         {
             return c1.getColor().compareTo(c2.getColor());
         }
     }
    

    您将字符串更改为 PaintColor,然后在主列表中您的汽车列表变为:

    carList.add(new CarSort("Ford Figo",PaintColor.SILVER));
    
    ...
    
    Collections.sort(carList, new ColorComparator());
    

    【讨论】:

    • 我将如何运行此示例。在 ColorComparator 中未访问 PaintColors。您能否说明主要方法的外观。
    • 输出是什么?总是先银吗?
    • @Deepak:是的,enum 值的自然顺序是定义其值的顺序。
    • @SeanPatrickFloyd 我不认为依赖枚举的自然顺序是最佳实践。
    • @mike 我不同意,但两种观点都有有效的论据
    【解决方案2】:

    这个怎么样:

    List<String> definedOrder = // define your custom order
        Arrays.asList("Red", "Green", "Magenta", "Silver");
    
    Comparator<Car> comparator = new Comparator<Car>(){
    
        @Override
        public int compare(final Car o1, final Car o2){
            // let your comparator look up your car's color in the custom order
            return Integer.valueOf(
                definedOrder.indexOf(o1.getColor()))
                .compareTo(
                    Integer.valueOf(
                        definedOrder.indexOf(o2.getColor())));
        }
    };
    

    原则上,我同意使用enum 是一种更好的方法,但这个版本更灵活,因为它允许您定义不同的排序顺序。

    更新

    Guava 已将此功能融入其 Ordering 类:

    List<String> colorOrder = ImmutableList.of("red","green","blue","yellow");
    final Ordering<String> colorOrdering = Ordering.explicit(colorOrder);
    Comparator<Car> comp = new Comparator<Car>() {
        @Override
        public int compare(Car o1, Car o2) {
            return colorOrdering.compare(o1.getColor(),o2.getColor());
        }
    }; 
    

    这个版本比较简洁。


    再次更新

    Java 8 让 Comparator 更加简洁:

    Comparator<Car> carComparator = Comparator.comparing(
            c -> definedOrder.indexOf(c.getColor()));
    

    【讨论】:

    【解决方案3】:

    在线比较器 ...

    List<Object> objList = findObj(name);
    Collections.sort(objList, new Comparator<Object>() {
        @Override
        public int compare(Object a1, Object a2) {
            return a1.getType().compareToIgnoreCase(a2.getType());
        }
    });
    

    【讨论】:

      【解决方案4】:

      我认为可以这样做:

      class ColorComparator implements Comparator<CarSort>
      {
          private List<String> sortOrder;
          public ColorComparator (List<String> sortOrder){
              this.sortOrder = sortOrder;
          }
      
          public int compare(CarSort c1, CarSort c2)
          {
              String a1 = c1.getColor();
              String a2 = c2.getColor();
              return sortOrder.indexOf(a1) - sortOrder.indexOf(a2);
           }
       }
      

      对于排序使用这个:

      Collections.sort(carList, new ColorComparator(sortOrder));
      

      【讨论】:

        【解决方案5】:

        我不得不做一些类似于 Sean 和 ilalex 的回答。
        但是我有太多选项可以显式定义排序顺序,并且只需要以指定的(非自然)顺序将某些条目浮动到列表的前面。
        希望这对其他人有帮助。

        public class CarComparator implements Comparator<Car> {
        
            //sort these items in this order to the front of the list 
            private static List<String> ORDER = Arrays.asList("dd", "aa", "cc", "bb");
        
            public int compare(final Car o1, final Car o2) {
                int result = 0;
                int o1Index = ORDER.indexOf(o1.getName());
                int o2Index = ORDER.indexOf(o2.getName());
                //if neither are found in the order list, then do natural sort
                //if only one is found in the order list, float it above the other
                //if both are found in the order list, then do the index compare
                if (o1Index < 0 && o2Index < 0) result = o1.getName().compareTo(o2.getName());
                else if (o1Index < 0) result = 1;
                else if (o2Index < 0) result = -1;
                else result = o1Index - o2Index;
                return result;
            }
        
        //Testing output: dd,aa,aa,cc,bb,bb,bb,a,aaa,ac,ac,ba,bd,ca,cb,cb,cd,da,db,dc,zz
        }
        

        【讨论】:

          【解决方案6】:

          我会这样做:

          List<String> order = List.of("Red", "Green", "Magenta", "Silver");
          
          Comparator.comparing(Car::getColor(), Comparator.comparingInt(c -> order.indexOf(c)))
          

          所有功劳归@Sean Patrick Floyd :)

          【讨论】:

            【解决方案7】:

            在 Java 8 中,您可以执行以下操作:

            你首先需要一个枚举:

            public enum Color {
                BLUE, YELLOW, RED
            }
            

            汽车类:

            public class Car {
            
                Color color;
            
                ....
            
                public Color getColor() {
                    return color;
                }
            
                public void setColor(Color color) {
                    this.color = color;
                }
            }
            

            然后,使用您的汽车列表,您可以简单地执行以下操作:

            Collections.sort(carList, Comparator:comparing(CarSort::getColor));
            

            【讨论】:

            • 这不是自定义排序。
            • 此外,这不是一种“功能性”的方式......这有副作用!!
            【解决方案8】:

            定义一个枚举类型为

            public enum Colors {
                 BLUE, SILVER, MAGENTA, RED
            }
            

            color 的数据类型从String 更改为Colors 将颜色的getter和setter方法的返回类型和参数类型更改为Colors

            如下定义比较器类型

            static class ColorComparator implements Comparator<CarSort>
            {
                public int compare(CarSort c1, CarSort c2)
                {
                    return c1.getColor().compareTo(c2.getColor());
                }
            }
            

            添加元素到List后,调用Collection的sort方法,传入list和comparator对象作为参数

            Collections.sort(carList, new ColorComparator()); 然后使用ListIterator打印。

            全类实现如下:

            package test;
            
            import java.util.ArrayList;
            import java.util.Collections;
            import java.util.Comparator;
            import java.util.List;    
            import java.util.ListIterator;
            
            public class CarSort implements Comparable<CarSort>{
            
                String name;
                Colors color;
            
                public CarSort(String name, Colors color){
                    this.name = name;
                    this.color = color;
                } 
            
                public String getName() {
                    return name;
                }
                public void setName(String name) {
                    this.name = name;
                }
                public Colors getColor() {
                    return color;
                }
                public void setColor(Colors color) {
                    this.color = color;
                }
            
                //Implement the natural order for this class
                public int compareTo(CarSort c)
                {
                    return getName().compareTo(c.getName());
                }
            
                static class ColorComparator implements Comparator<CarSort>
                {
                    public int compare(CarSort c1, CarSort c2)
                    {
                        return c1.getColor().compareTo(c2.getColor());
                    }
                }
            
                public enum Colors {
                     BLUE, SILVER, MAGENTA, RED
                }
            
                 public static void main(String[] args)
                 {
                     List<CarSort> carList = new ArrayList<CarSort>();
                     List<String> sortOrder = new ArrayList<String>();
            
                     carList.add(new CarSort("Ford Figo",Colors.SILVER));
                     carList.add(new CarSort("Santro",Colors.BLUE));
                     carList.add(new CarSort("Honda Jazz",Colors.MAGENTA));
                     carList.add(new CarSort("Indigo V2",Colors.RED));
                     Collections.sort(carList, new ColorComparator());
            
                     ListIterator<CarSort> itr=carList.listIterator();
                     while (itr.hasNext()) {
                        CarSort carSort = (CarSort) itr.next();
                        System.out.println("Car colors: "+carSort.getColor());
                    }
                 }
            }
            

            【讨论】:

              【解决方案9】:

              只使用简单的循环:

              public static void compareSortOrder (List<String> sortOrder, List<String> listToCompare){
                      int currentSortingLevel = 0;
                      for (int i=0; i<listToCompare.size(); i++){
                          System.out.println("Item from list: " + listToCompare.get(i));
                          System.out.println("Sorting level: " + sortOrder.get(currentSortingLevel));
                          if (listToCompare.get(i).equals(sortOrder.get(currentSortingLevel))){
              
                          } else {
                              try{
                                  while (!listToCompare.get(i).equals(sortOrder.get(currentSortingLevel)))
                                      currentSortingLevel++;
                                  System.out.println("Changing sorting level to next value: " + sortOrder.get(currentSortingLevel));
                              } catch (ArrayIndexOutOfBoundsException e){
              
                              }
              
                          }
                      }
                  }
              

              List 中的排序顺序

              public static List<String> ALARMS_LIST = Arrays.asList(
                          "CRITICAL",
                          "MAJOR",
                          "MINOR",
                          "WARNING",
                          "GOOD",
                          "N/A");
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-05-12
                • 2016-05-24
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多