Как вставить новый элемент в упорядоченный список и сдвинуть все остальные объекты в Java?

#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 атрибутом a User ?

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() of List . Итак, ваше решение сработало, и я думаю, что это намного элегантнее, чем мое решение. Спасибо.

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() )
);