Сортируемый набор, индексируемый по идентификатору свойства объекта

#java #collections

#java #Коллекции

Вопрос:

Представьте себе такой простой класс.

 class Observation 
{
   String id;
   Double value;
   Integer quantity;

   //getters only


}
 

Я хотел бы иметь некоторую отсортированную коллекцию наблюдений.

 SortedSet<Observations> sortedSet = new TreeSet<Observation>(
            Comparator.comparing(Observation::getValue)
                .thenComparing(Observation::getQuantity));
 

Затем я получил сообщение о том, что наблюдение с некоторым идентификатором изменило значение. Идея состоит в том, чтобы удалить старое наблюдение и добавить новое с обновленным значением.

Я придумал несколько решений:

  1. используйте Map<Строка, объект> для создания сопоставления между идентификатором и экземпляром объекта, хранящимся в SortedSet
 
    observation = new Observation(id, value, quantity)
    map.put(observation.getId(), observation)
    sortedSet.add(observation)
    
    //then I can remove observation with given id with
    sortedSet.remove(map.get(someId))

 
  1. Добавьте методы equals и hashCode для наблюдения, основанные только на Observation.id ; Однако я чувствую, что это не элегантное решение.

Комментарии:

1. Если это работает, и вам просто нужен некоторый обзор, потому что вы чувствуете, что это недостаточно элегантно, тогда Code Review может подойти для запроса.

Ответ №1:

Моим любимым выбором было бы ваше второе решение. Рациональным является то, что вам не нужно поддерживать обновление двух коллекций, и переопределения #equals на основе сравнения идентификаторов наблюдений должно быть достаточно.

Счастливого кодирования.

Комментарии:

1. Оператору все равно придется поддерживать две коллекции, так как TreeSet ему все равно hashCode / equals .

Ответ №2:

У вас есть коллекция Observation экземпляров , которые сортируются по value и quantity , но явно не по id .

Сначала вы должны добавить Observation.id в компаратор, в который вы переходите TreeSet . Это потому, что можно иметь два Observation экземпляра с одинаковыми value и quantity разными идентификаторами.

Вы упоминаете, что получаете сообщение о том, что Observation с некоторым идентификатором изменилось. Объект Observation с этим идентификатором в SortedSet now должен быть перемещен в новую позицию на основе его нового value и quantity . Но нет эффективного способа найти Observation с определенным идентификатором в SortedSet .

Одна вещь, которую вы могли бы сделать, это просто перебирать SortedSet , пока не найдете Observation идентификатор, который вы хотите обновить. Затем вы можете удалить его и повторно добавить. Преимущество этого заключается в простоте, но операция поиска SortedSet будет O (N), что может быть не тем, что вы хотите.

Если вам нужен более эффективный способ обновления SortedSet, вы могли бы поддерживать HashMap идентификаторы Observation экземпляров. Когда вы получаете уведомление о том, что объект Observation был изменен, найдите его в HashMap по его идентификатору (мы предполагаем, что экземпляр в не HashMap изменен и что вы получаете другой Observation экземпляр с тем же идентификатором, но с другими значениями), удалите его из SortedSet , обновите / замените экземпляр в HashMap и добавьтеновый / обновленный экземпляр в SortedSet .

(Обновлено с учетом ввода от @Holger, спасибо!)

Комментарии:

1. При вашем последнем подходе вам придется сначала удалить идентификатор из отсортированного набора, прежде чем обновлять карту.

2. Вы обеспокоены тем, что обновление первого обновления наблюдения приведет к тому, что другой поток потенциально увидит несортированный SortedSet? Я понял, что здесь есть потенциальные проблемы с параллелизмом, но я не поднимал их, потому что было неясно, обновляются ли экземпляры наблюдения на месте или нет, и есть ли другие потоки, обращающиеся к данным.

3. Здесь не требуется многопоточность. Когда вы меняете карту перед операцией удаления, компаратор, основанный на значениях карты, уже не сможет найти объект для удаления. Это именно та проблема, которую вы хотите решить (иначе зачем беспокоиться об удалении и повторном добавлении)…

4. Хорошо, теперь я понимаю вашу точку зрения. Вы правы. На самом деле, похоже, нет никакого смысла хранить идентификаторы в SortedSet вообще.