#java #list
#java #Список
Вопрос:
Предположим, у меня есть этот простой класс:
public class User implements Comparable<User> {
private String name;
private Integer order;
public User(String name, Integer order) {
this.name = name;
this.order = order;
}
//...Getters and Setters ommited
@Override
public int compareTo(User user) {
return this.order.compareTo(user.getOrder());
}
}
Всего два атрибута, имя пользователя и порядок. Этот атрибут order
будет использоваться для определения положения пользователя внутри списка. Затем я создам неупорядоченный LinkedList()
из них:
private static List<User> unorderedList() {
final List<User> users = new LinkedList<>();
users.add(new User("Joe", 5));
users.add(new User("John", 2));
users.add(new User("Maria", 8));
users.add(new User("Kevin", 7));
users.add(new User("Sophia", 9));
users.add(new User("James", 1));
users.add(new User("Adrian", 3));
return users;
}
Теперь мне нужно создать и вставить новый User
в мой список.
User u = new User("David", 2);
Но, прежде чем я вызову add()
метод, я должен что-то сделать.
Я должен упорядочить этот список (вот почему я реализовал Comparable
в классе User), и я должен обновить атрибут order
, чтобы он был последовательным. Поэтому, когда я вставляю своего нового пользователя в список, мне нужно получить конечный результат, подобный этому:
1 - James // No Change
2 - David // New user inserted
3 - John // Was order 2, become 3
4 - Adrian // Was order 3, become 4
5 - Joe // No Change
6 - Kevin // There was no 6. Kevin was 7 so he become 6
7 - Maria // Was 8
8 - Sophia - // Was 9
РЕДАКТИРОВАТЬ 1: что я пробовал
Я попытался перебрать список и сравнить порядок пользователей в списке с порядком новых пользователей. Новый пользователь имеет приоритет в позиции внутри списка.
final List<User> unorderedUsers = MainApp.unorderedList();
final AtomicInteger currentOrder = new AtomicInteger(1);
final User newUser = new User("David", 2);
Collections.sort(unorderedUsers);
unorderedUsers.forEach(user -> {
if (user.getOrder().equals(newUser.getOrder())) {
user.setOrder(user.getOrder() 1);
} else {
user.setOrder(currentOrder.get());
}
currentOrder.incrementAndGet();
});
unorderedUsers.add(newUser);
Collections.sort(unorderedUsers);
System.out.println(String.format("Ordered with new User List -> %s", unorderedUsers));
Однако новый порядок пользователя дублируется. Я все еще пытаюсь решить, как создать новый последовательный порядок. Результат моего кода:
'James', order=1
'David', order=2
'John', order=3
'Adrian', order=3
'Joe', order=4
'Kevin', order=5
'Maria', order=6
'Sophia', order=7
ПРАВКА 2 — Возможное найденное решение
Я не знаю, охватывает ли это решение все сценарии, но я разделяю их на два этапа. Я знаю, что это немного дорого, но это то, что у меня есть.
private void insertNewUser(final List <User> usersList, final User newUser) {
final AtomicBoolean canShift = new AtomicBoolean(false);
usersList.forEach(user ->{
if (user.getOrder().equals(newUser.getOrder()) || canShift.get()) {
user.shiftOrder();
canShift.set(true);
}
});
usersList.add(newUser);
Collections.sort(usersList);
}
private void organizeOrder(final List <User> usersList) {
final AtomicInteger currentOrder = new AtomicInteger(1);
usersList.forEach(user -> user.setOrder(currentOrder.getAndIncrement()));
}
Затем просто вызовите:
this.insertNewUser(...)
this.organizeOrder(...)
Комментарии:
1. И что вы пытались добиться этого? SO не является сервисом кодирования, но он помогает тем, кто пытался
2. Если я могу спросить, почему атрибут a является
order
атрибутом aUser
?3. @azro добавил, что я уже пробовал. Я все еще пытаюсь
4. @MCEmperor это пример. Однако мой клиент хочет выполнить упорядочение объектов вручную.
Ответ №1:
Вам не нужно реализовывать Comparable
интерфейс. Вы можете сортировать с помощью Comparator
:
users.addFirst(newUser);
// We're using addFirst here, because we want to make sure
// that the new user comes BEFORE possible users with the
// same order
AtomicInteger inc = new AtomicInteger();
users.stream()
.sorted(Comparator.comparing(User::getOrder))
.map(user -> {
user.setOrder(inc.incrementAndGet());
return user;
})
.collect(Collectors.toList();
В приведенном выше коде происходит вот что: сначала AtomicInteger
создается an , что помогает нам предоставлять пользователям новые порядковые номера. Затем мы сортируем поток по порядковому номеру User
. Затем мы получаем новый порядковый номер из AtomicInteger
, и мы устанавливаем order
свойство с этим номером. Наконец, мы собираем это в список.
addFirst()
гарантирует, что новый пользователь добавлен в начало списка. Это потому, что в окончательно отсортированном списке мы хотим, чтобы новый пользователь появлялся перед любым другим пользователем с тем же порядком. Поскольку сортировка является стабильной сортировкой, элементы с одинаковыми порядковыми номерами отображаются в том же порядке, что и несортированный поток.
В качестве альтернативы, вместо addFirst()
, вы могли бы использовать
newUser.setOrder(newUser.getOrder() - 1);
users.add(newUser);
вместо этого.
Комментарии:
1. Я попробовал ваше решение, но когда я передаю «David» с порядком 2, Дэвид оказывается в позиции 3. Он должен быть 2, а «Джон» 3.
2. @humungs Даже с
addFirst
вместоadd
?3. Вот и все! Необходимо
addFirst()
. Я использовалadd()
ofList
. Итак, ваше решение сработало, и я думаю, что это намного элегантнее, чем мое решение. Спасибо.4. @humungs Не забудьте принять ответ, если это то, что вы искали.
5. Я просто проводил некоторое модульное тестирование, чтобы убедиться, что я охватываю все сценарии. Спасибо! Ответ принят!
Ответ №2:
Вы не обновляете пользователей, имеющих порядок выше, чем порядок (2) нового пользователя. Сортировка не обновляет значение ваших объектов. Вы можете попробовать это.
Collections.sort(users);
users.add( newUser.getOrder()-1 , newUser );
AtomicInteger index = new AtomicInteger(1);
users.forEach(
user -> user.setOrder( index.getAndIncrement() )
);