Compare partial object in an ArrayList Java

1.2k views Asked by At

I have an Object as follows:

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;
    }
}

I am storing multiple objects in a List. While inserting a new record, I need to check if the list already has an object with ONLY the same title and date, and replace the time in it.

I am looking for any solution which can achieve O(1) time.

3

There are 3 answers

0
Artem Barger On BEST ANSWER

Searching in ArrayList for existing element will take you O(n) in case of sorted ArrayList (e.g. you maintain records sorted) it will require O(logn) time. Therefore to achieve desired functionality I'd use Map structure, indexing by title and then by date. Something like this:

// 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);
   }
}

Using Map of Map will prevent from you the need to override equals and hashCode methods, while I'd agree that Map<String, Map<Date, Record>> might look a bit fancy or weird. While will provide you with ability to update the records or check for existence within O(1) time. Additional nit is that you do not need to create a record to check for existence or for update, you can directly use Title and Date to retrieve what you needed.

14
armnotstrong On

You could do that by a HashSet

and implement the

@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;

    }

And use a hashset to insert

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

Then you could convert the HashSet to the List you want.

0
Adrian Shum On

Make use of a Map implementation that gives you O(1) access, like HashMap or ConcurrentHashMap .

Psuedo-code:

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