Java List with Objects - find and replace (delete) entry if Object with certain attribute already exists

13,356

Solution 1

A Map is easiest, but a Set reflects your logic better. In that case I'd advice a Set.

There are 2 ways to use a set, depending on the equals and hashCode of your data object.

If YourObject already uses the ID object to determine equals (and hashCode obeys the contract) you can use any Set you want, a HashSet is probably best then.

If YourObjects business logic requires a different equals, taking into account multiple fields beside the ID field, then a custom comparator should be used. A TreeSet is a Set which can use such a Comparator.

An example:

Comparator<MyObject> comp = new Comparator<MyObject>{
  public int compare(MyObject o1, MyObject o2) {
    // NOTE this compare is not very good as it obeys the contract but
    // is not consistent with equals. compare() == 0 -> equals() != true here
    // Better to use some more fields
    return o1.getId().hashCode() < o2.getId().hashCode();
  }
  public boolean equals(Object other) {
    return 01.getId().equals(o2.getId());
  }
}

Set<MyObject> myObjects = new TreeSet(comp);

EDIT I have updated the code above to reflect that id is not an int, as suggested by the question.

Solution 2

You could use a HashMap (or LinkedHashMap/TreeMap if order is important) with a key of ID and a value of Objects. With generics that would be HashMap<Object, Objects>();

Then you can use

if (map.containsKey(ID)) {
    map.remove(ID);
}

map.put(newID, newObject);

Alternatively, you could continue to use a List, but we can't just modify the collection while iterating, so instead we can use an iterator to remove the existing item, and then add the new item outside the loop (now that you're sure the old item is gone):

List<Objects> syncList = ...

for (Iterator<Objects> iterator = syncList.iterator(); iterator.hasNext();) {
    Objects current = iterator.next();

    if (current.getID().equals(ID)) {
        iterator.remove();
    }
}

syncList.add(newObject);

Solution 3

You could use a HashSet to store the objects and then override the hashCode method in the class that the HashSet will contain to return the hashcode of your identifying field.

Solution 4

And you can't use a Set to have only the first one stored ?

because it basically is precisely what you require.

Share:
13,356
Gnark
Author by

Gnark

Updated on September 04, 2022

Comments

  • Gnark
    Gnark almost 2 years

    I've been working all day and I somehow can't get this probably easy task figured out - probably a lack of coffee...

    I have a synchronizedList where some Objects are being stored. Those objects have a field which is something like an ID. These objects carry information about a user and his current state (simplified).

    The point is, that I only want one object for each user. So when the state of this user changes, I'd like to remove the "old" entry and store a new one in the List.

    protected static class Objects{
        ...
        long time;
        Object ID;
        ... 
        }
    

    ...

    if (Objects.contains(ID)) {
                Objects.remove(ID);
                Objects.add(newObject);
            } else {
                Objects.add(newObject);
            }
    

    Obviously this is not the way to go but should illustrate what I'm looking for...
    Maybe the data structure is not the best for this purpose but any help is welcome!


    EDIT:
    Added some information...
    A Set does not really seem to fit my purpose. The Objects store some other fields besides the ID which change all the time. The purpose is, that the list will somehow represent the latest activities of a user. I only need to track the last state and only keep that object which describes this situation.
    I think I will try out re-arranging my code with a Map and see if that works...

    • extraneon
      extraneon over 14 years
      Yes, the Set's add method is a problem in your case. Good luck with the Map!
    • Gnark
      Gnark over 14 years
      thanks, it worked like a charm - the "pseudo-iteration" over a HashMap is a little iffy but works as well :-)
  • Dan
    Dan over 14 years
    If an instance of Objects has other properties (besides ID), then he does not need the first one stored, but the latest one with the same ID value.
  • extraneon
    extraneon over 14 years
    If you really need a Set then a TreeSet with comparator can also be used, and might better fit the model.
  • Steve Kuo
    Steve Kuo over 14 years
    Why does compare using the object's hash code? This is just wrong.