Java 8 - настраиваемая сортировка на основе определенного заказа
Я хотел бы отсортировать список пользователей по их статусу, но порядок должен быть основан на порядке, который я установил.
Я хочу установить порядок списка,
Порядок должен быть 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, поскольку этот порядок не является ни в порядке возрастания, ни в порядке убывания.
Ответы
Ответ 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));
Ответ 3
Предполагая, что 1
, 0
и 5
будут единственными значениями status
, AJNeufeld сделал отличное замечание в своем комментарии; они заявили, что вы можете использовать уравнение для отображения каждого значения в порядке возрастания. В этом случае уравнение будет (x - 1)^2
где x
- это значение status
:
users.sort(Comparator.comparingDouble(user -> Math.pow(user.getStatus() - 1, 2)));
Если бы вы напечатали содержимое user
после вызова приведенного выше фрагмента, вы получите:
[Пользователь [имя пользователя = A, статус = 1], Пользователь [имя пользователя = D, статус = 1], Пользователь [имя пользователя = C, статус = 0], Пользователь [имя пользователя = F, статус = 0], Пользователь [имя пользователя = B, status = 5], Пользователь [username = E, status = 5]]
Ответ 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
Как вы уже упоминали, вам нужен пользовательский порядок, а это значит, что вам нужно где-то определить этот порядок в HashMap < Status, Rank >> или одним простым способом добавить еще один атрибут, скажем, Integer rank; и вы можете определить ранг на основе вашего заказа для атрибута статуса, например, скажем users.add(new User ("A", 1,0)); здесь статус 1 самый сортированный в порядке и его ранг = 0. И тогда вы можете использовать Comparator по атрибуту ранга.
Например:
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);
}
}