Сравнить частичный объект в ArrayList Java

У меня есть объект следующим образом:

public class Record{
    Int ID;
    String title;
    Date date;
    Duration time;

    public Record createRecord(int ID, String title, Date date, Duration time){
        this.ID= ID;
        this.title = title;
        this.date = date;
        this.time = time;
        return this;
    }
}

Я храню несколько объектов в списке. При вставке новой записи мне нужно проверить, есть ли в списке уже объект с ТОЛЬКО одинаковыми заголовком и датой, и заменить время в нем.

Я ищу любое решение, которое может достичь O(1) времени.

3 ответа

Решение

Поиск в ArrayList для существующего элемента займет у вас O(n) в случае отсортированного ArrayList (например, вы сохраняете отсортированные записи) это потребует O(logn) времени. Поэтому для достижения желаемой функциональности я бы использовал структуру карты, индексацию по названию, а затем по дате. Что-то вроде этого:

// Create general records DB
Map<String, Map<Date, Record>> records = new HashMap<>();

// Create sub DB for records with same ID
Map<Date, Record> subRecords = new HashMap<>();

// Assuming you've got from somewhere id, title and rest of the parameters
subRecords.put(recordDate, new Record(id, title, time, duration));
records.put(recordId, subRecords)

// Now checking and updating records as simple as
sub = records.get(someTitle); // Assuming you've got someTitle
if (sub != null) {
   record = sub.get(someDate); // Same for someDate
   if (record != null) {
       record.updateTime(newTime);
   }
}

Использование Map of Map избавит вас от необходимости переопределять методы equals и hashCode, хотя я бы согласился, что Map<String, Map<Date, Record>> может выглядеть немного причудливо или странно. Хотя предоставит вам возможность обновить записи или проверить наличие в течение O(1) времени. Дополнительным преимуществом является то, что вам не нужно создавать запись для проверки существования или обновления, вы можете напрямую использовать заголовок и дату, чтобы получить то, что вам нужно.

Вы можете сделать это HashSet

и реализовать

@Override
    public boolean equals(Object obj) {
        if(this == obj) return true;
        if(!(obj instanceof Record)) return false;
        Record otherRecord = (Record)obj;
        return (this.time.equals(otherRecord.time) && this.title.equals(otherRecord.title));
    }

    @Override
    public int hashCode() {        
        int result = titile != null ? titile.hashCode() : 0;
        result = 31 * result + (time != null ? time.hashCode() : 0);
        return result;

    }

И использовать хешсет для вставки

   HashSet hset = new HashSet<Record>();
   if(!hset.add(record)){
        hset.remove(record);
        hset.add(record);
   }

Затем вы можете преобразовать HashSet в список, который вы хотите.

Используйте реализацию Map, которая дает вам O(1) доступ, как HashMap или же ConcurrentHashMap,

Псевдопользователей-код:

class Record {
    static class Key {
        Date date
        String title
        // proper hashCode and equals
    }
    Date date
    String title
    int id
    Time time
    Key getKey() {...}
}


Map<Record.Key, Record> recordMap = new HashMap<>();
for (record : records) {
    recordMap.merge(record.getKey(), record, 
                   (oldRecord, newRecord) -> oldRecord.setTime(newRecord.getTime()));
}
Другие вопросы по тегам