9

I have an ArrayList which contains element of a class Event. Event has two properties, Name and Timestamp. The list now shows ALL events. I want to remove the duplicates with the same name, but different timestamp, and put them in another list. This way the user can click on an event with that name, then select a date.

I am already overriding the function equals (that compares name AND timestamp) for some other functionalities in my application.

How can I solve this?

5
  • have you tried using HashSet instead of ArrayList? Commented Apr 30, 2015 at 10:22
  • do you have any situation like same name and same time stamp and you want to save that also in list ? Commented Apr 30, 2015 at 10:22
  • which Events you must keep? first found? Commented Apr 30, 2015 at 10:22
  • Please follow this link here. This shows the alternative for a list. If possible you can go by this way. Comment otherwise Commented Apr 30, 2015 at 10:27
  • 1
    Why was this marked as a duplicate? The duplicate link is not answering the question, only a small part of it, and it's doing it wrong based on the other part. I quote: "I want to remove the duplicates with the same name, but different timestamp, and put them in another list.". It seems that the filtering isn't even the actual goal here: "This way the user can click on an event with that name, then select a date." Commented Apr 30, 2015 at 12:14

3 Answers 3

31

If you already have your own equals method you can't use Hash collections. You must manually check it implementing a nested loop:

List<Event> allEvents = // fill with your events.
List<Event> noRepeat = new ArrayList<Event>();

for (Event event : allEvents) {
    boolean isFound = false;
    // check if the event name exists in noRepeat
    for (Event e : noRepeat) {
        if (e.getName().equals(event.getName()) || (e.equals(event))) {
            isFound = true;        
            break;
        }
    }
    if (!isFound) noRepeat.add(event);
}
Sign up to request clarification or add additional context in comments.

5 Comments

I dont think that this is complete solution. I want remove the duplicates with the same name, but different timestamp, and put them in another list You have to check also timmestamps for equality
he has an equals method to check both parameters, he needs to delete same named events from a list: OP says: I want remove the duplicates with the same name, but different timestamp thats what my method do...
Yeah but since ArrayList can contain duplicates condition should be if (e.getName().equals(event.getName() || e.equals(event)) to remove also different objects with same name and timestamp
actually it goes against natural logic, but it's true... nice catch!
@JordiCastilla a nice way to do what you're doing is use a custom Comparator<Event> (to compare) with a TreeSet<Event> (to create a set using that Comparator). It also enforces clarity since the idea is conveyed by using the right interfaces. See last part of my answer.
2

I think you're using the wrong data structure. You want to use an implementation of Map and map String (name) to Set<Event> (unique events).

Here is how we test it:

  1. Create some events.
  2. Create Map<String, Set<Event>. this will allow us to map a name to unique events.
  3. Fill the mapping.

So first, we create a collection of events to test:

    Collection<Event> events = new ArrayList<Event>() {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        {
            add(new Event("FirstCategory", new Timestamp(0)));
            add(new Event("FirstCategory", new Timestamp(0)));
            add(new Event("FirstCategory", new Timestamp(1)));
            add(new Event("SecondCategory", new Timestamp(2)));
        }
    };

Now we create a mapping between a name and all of it's corresponding unique events:

    Map<String, Set<Event>> eventsByName = new HashMap<String, Set<Event>>();

Now we fill the mapping with unique events for each name:

    for (Event e : events) {
        if (!eventsByName.containsKey(e.getName())) {
            // create new set by name
            eventsByName.put(e.getName(), new HashSet<Event>());

        }
        // add event to existing Set.
        // duplicates will be dropped since it's a `Set`
        eventsByName.get(e.getName()).add(e);

    }

Check what we got:

    System.out.println(eventsByName);

Output:

{
    SecondCategory=[
        Event [name=SecondCategory, timestamp=1970-01-01 02:00:00.002]
    ],
    FirstCategory=[
        Event [name=FirstCategory, timestamp=1970-01-01 02:00:00.0],
        Event [name=FirstCategory, timestamp=1970-01-01 02:00:00.001]
    ]
}

Tip 1:

To get the list of names you only need to look at the Map's keys, which are effectively a Set as well:

System.out.println(eventsByName.keySet());

Output:

[SecondCategory, FirstCategory]

Tip 2:

If this isn't what you expect, and you want a different definition of uniqueness, you can implement a Comparator<Event> and use that with a TreeSet<Event> instead of using the HashSet<Event> which can not accept a custom Comparator.

So if you have a class:

class EventByRandomDefinitionComparator implements Comparator<Event>{
    // implementation ...
}

This is all that needs to be done when filling the mapping:

    // create different comparison mechanism
    Comparator<Event> comparator = new EventByRandomDefinitionComparator();

    for (Event e : events) {
        if (!eventsByName.containsKey(e.getName())) {
            // create new set by name
            // changed Set implementation to use new comparator
            eventsByName.put(e.getName(), new TreeSet<Event>(comparator)));
        }
        // add event to existing Set.
        // duplicates will be dropped since it's a `Set`
        eventsByName.get(e.getName()).add(e);

    }

Good luck.

2 Comments

Thank you for your comprehensive answer. It would have been a lot easier if I used a map from the beginning. Another answer solved my question, but I will keep Map in my mind for the future. I will use a Map now to link the same event with multiple timestamps.
Whatever is stopping you from using the right solution now, is only going to get worse if you add more code that is based on the wrong implementation. Using the right tools can make code easier to maintain, test and understand. If this answer is lacking something you're trying to accomplish add it to your question and I can try and extend the answer to include it.
-1

You should override your equals() and hashCode() methods in your Event class and add all the objects in a Set rather than a List. A Set will not allow the duplicate objects, provided you have properly overridden the equals() and hashCode().

1 Comment

OP have to use equals for another purposes... please read carefully

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.