caleb baker
caleb baker

Reputation: 144

How do I remove duplicates from tree set with Custom Objects

I have an ArrayList (cntct) of ParseMessage's. ParseMessage has the

private long dateSent;
private String contact;
private String body;

with the getters and setters generated by eclipse. I am trying to get the most recent message from each contact. So I decided to do it as such

SortedSet<ParseMessage> cntctList = new TreeSet<ParseMessage>(new Comparator<ParseMessage>() {
@Override
public int compare(ParseMessage o1, ParseMessage o2)
{   
    if(o1 == null || o2 == null)
        return 0;
    if(o1.getContact().equals(o2.getContact()))
        return 0;
    if(o1.getDateSent() <= o2.getDateSent())
        return 1;
    return -1;
}           
});
cntctList.addAll(cntct);

I seemed to have missed something in this though, as I am still getting a limited number of duplicates. I am using maybe 100 messages with 5 contacts and the set ends up with a size of 7

EDIT:

ParseMessage does override .equals and .hasCode As such

@Override
public int hashCode() {
    return getContact().hashCode();
}

@Override
public boolean equals(Object e) {
    if(!(e instanceof ParseMessage))
    {
        return false;
    }

    return ((ParseMessage) e).getContact().equals(getContact());
}

END:

Also this is for a web based call. If anyone see's a way to make this faster then I would love to hear ideas.

Upvotes: 1

Views: 263

Answers (1)

Andreas
Andreas

Reputation: 159086

The code in the question doesn't work because the compare method violates the rules, e.g.

The implementor must also ensure that the relation is transitive: ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.

For example:
compare(A1, B2) would return <0 because A != B && 1 < 2
compare(B2, A3) would return <0 because B != A && 2 < 3
compare(A1, A3) would return 0 because A == A, but the rules require it to return <0

When the rules are broken, the result is non-deterministic.


To build a collection of ParseMessage with only the most recent message from each contact, you should create a Map.

List<ParseMessage> cntct = /*...*/;

// Build map of contact to most recent message
Map<String, ParseMessage> cntctMap = cntct.stream().collect(Collectors.toMap(
        ParseMessage::getContact,
        Function.identity(),
        (a, b) -> a.getDateSent() >= b.getDateSent() ? a : b
));

If a collection of messages is needed, call values():

Collection<ParseMessage> cntctList = cntctMap.values();

Upvotes: 3

Related Questions