【问题标题】:Java 8 - customised sort based on specific orderJava 8 - 基于特定顺序的自定义排序
【发布时间】:2018-11-12 03:59:34
【问题描述】:

我想根据用户的状态对用户列表进行排序,但顺序必须基于我设置的顺序。

我要设置列表的顺序,

顺序应该是1、0、5。我们还应该记住订购用户名。

List<User> users = new ArrayList();
         users.add(new User("A", 1));
         users.add(new User("B", 5));
         users.add(new User("C", 0));
         users.add(new User("D", 1));
         users.add(new User("E", 5));
         users.add(new User("F", 0));

这是用户类

public class User {
         private String username;
         private Integer status;
     }

应该是这样的

[
    {
      "username": "A",
      "status": 1
    },
    {
       "username": "D",
       "status": 1
    },
    {
       "username": "C",
       "status": 0
    },
    {
       "username": "F",
       "status": 0
    },
    {
       "username": "B",
       "status": 5
    },
    {
       "username": "E",
       "status": 5
    }
]

我不确定是否可以使用 Comparator.comparing,因为这个既不是升序也不是降序。

【问题讨论】:

  • 是的,Comparator 可以处理,它只需要根据提供的两个值的比较返回+1/-1/0。最好的办法就是试一试
  • 如果 1,0,5 是唯一的状态编号,那么您可以使用比较器轻松排序。
  • 减1,然后平方。 1,0,5 -> 0, 1, 16 ... 很容易排序
  • @KennethC Compator 仅根据比较结果和您希望对值进行排序的顺序返回负数、正数或零值
  • @KennethC 查看Comparator.compare 的文档,了解不同返回值的含义(负数表示小于,零表示等于,正数表示大于)。

标签: java sorting java-8 comparator


【解决方案1】:

一种方法是按照您想要的顺序保存一个列表,并根据其索引对用户进行排序:

final List<Integer> order = Arrays.asList(1, 0, 5);
users.sort(
    Comparator.comparing((User u) -> order.indexOf(u.getStatus()))
              .thenComparing(User::getUsername));

请注意,虽然这种方法对于少数状态(就像您目前拥有的那样)应该是合理的,但如果存在大量状态并且您需要对每个状态执行 O(n) 搜索,它可能会减慢排序速度时间。一种性能更好的方法(尽管可以说没有那么圆滑)是使用地图:

final Map<Integer, Integer> order = new HashMap<>();
order.put(1, 0);
order.put(0, 1);
order.put(5 ,2);
users.sort(Comparator.comparing((User u) -> order.get(u.getStatus()))
                     .thenComparing(User::getUsername));

【讨论】:

    【解决方案2】:

    如果你不介意在你的项目中使用 Guava,你可以使用Ordering.explicit:

    users.sort(Ordering.explicit(1, 0, 5).onResultOf(User::getStatus));
    

    如果您也想按名称排序,请添加thenComparing

    users.sort(Ordering
            .explicit(1, 0, 5)
            .onResultOf(User::getStatus)
            .thenComparing(User::getUsername));
    

    【讨论】:

    • 我会这样做,主要是因为explicit 是一个非常清晰和“明确”的名称
    【解决方案3】:

    假设105 将是status 的唯一值,AJNeufeld 在their comment 中提出了一个很好的观点;他们说您可以使用方程式将每个值映射到升序。在这种情况下,等式将是(x - 1)^2,其中xstatus 的值:

    users.sort(Comparator.comparingDouble(user -> Math.pow(user.getStatus() - 1, 2)));
    

    如果你在调用上面的 sn-p 之后打印user 的内容,你会得到:

    [用户[用户名=A,状态=1],用户[用户名=D,状态=1],用户[用户名=C,状态=0],用户[用户名=F,状态=0],用户[用户名=B,状态=5],用户[用户名=E,状态=5]]

    【讨论】:

    • 为什么不只是 |x - 1|?
    • @ZhekaKozlov v^1...
    • @Holger 打扰一下?
    • @ZhekaKozlov value ^ 1 甚至比Math.abs(value - 1) 更简单(虽然两者的区别不如Math.pow 大)。
    • @Holger 0^1 &lt; 1^1(应该更大)
    【解决方案4】:

    你可以尝试一步一步来

    //order define here
    List<Integer> statusOrder= Arrays.asList(1,0,5,2);
    
    //define sort by status
    Comparator<User> byStatus = (u1, u2) -> {
        return Integer.compare(statusOrder.indexOf(u1.getStatus()), statusOrder.indexOf(u2.getStatus()));
    };
    
    //define sort by name
    Comparator<User> byName = Comparator.comparing(User::getUsername);
    
    //actualy sort
    users.sort(byStatus.thenComparing(byName));
    

    【讨论】:

      【解决方案5】:

      正如您所提到的,您需要自定义排序,这意味着您需要在 HashMapStatus,Rank>> 中定义排序的某个位置,或者以一种简单的方式添加一个属性,例如 Integer rank; 并且您可以根据状态属性的排序来定义排名,例如 users.add(new User("A", 1,0));这里状态 1 是按顺序排序的,它的 rank=0。然后你可以使用等级属性上的比较器

      例如:

      public class User {
          public String username;
          public Integer status;
          public Integer rank;
      
          public User(String username, Integer status, Integer rank) 
          { 
              this.username = username; 
              this.status = status; 
              this.rank = rank;
          } 
      }
      

      比较器类:

      class SortByRank implements Comparator<User> 
      { 
          // Used for sorting in ascending order of 
          // rank number 
          public int compare(User a, User b) 
          { 
              return a.rank - b.rank; 
          } 
      } 
      

      主类:

      class Main 
      { 
          public static void main (String[] args) 
          { 
               List<User> users = new ArrayList();
               users.add(new User("A", 1, 0));
               users.add(new User("B", 5, 2));
               users.add(new User("C", 0, 1));
               users.add(new User("D", 1, 0));
               users.add(new User("E", 5, 2));
               users.add(new User("F", 0, 1));
      
              System.out.println("Unsorted"); 
              for (int i=0; i<users.size(); i++) 
                  System.out.print(users.get(i).username); 
      
              Collections.sort(users, new SortByRank()); 
      
              System.out.println("\nSorted by Rank"); 
              for (int i=0; i<users.size(); i++) 
                  System.out.print(users.get(i).username); 
          } 
      } 
      

      【讨论】:

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