daniel sp
daniel sp

Reputation: 1000

Different Set collection based in different equals / hashcode

I want to have two Set collections holding unique objects based on different implementations of the equals/hashCode for the same kind of object.

For example, one Set would be only for the elements that have a different timestamp and the equals should return a.timestamp!=b.timestamp, but the other set could be only for elements that have different names with equals like a.name!=b.name.

Is there a trivial way to achieve this? How can you make custom equals for each different Set?

Upvotes: 2

Views: 99

Answers (4)

daniel sp
daniel sp

Reputation: 1000

Ok, I was wondering if there could be an easy way to specify the equals/hashcode to be used in a Set. I see no one has ever heard of such thing.

If this cannot be done, I can always use Map with the custom hashcode as key and then when I need to get the Collection I get the Map.values(). I wanted to avoid this because to keep memory usage low, but maybe it's the way...

Upvotes: 0

Simon Zambrovski
Simon Zambrovski

Reputation: 756

Create two wrapping value classes and put the equals and hashCode implementations there.

    public class Test {


    Set<NameBeanWrapper> names = new HashSet<Test.NameBeanWrapper>();
    Set<TimestampBeanWrapper> timestamps = new HashSet<Test.TimestampBeanWrapper>();

    public void store(Set<Bean> initial) {
      for (Bean bean : initial) {
        names.add(new NameBeanWrapper(bean));
        timestamps.add(new TimestampBeanWrapper(bean));
      }
    }

    public static class Bean {
      String name;
      Long timestamp;
      public String getName() {
        return name;
      }
      public void setName(String name) {
        this.name = name;
      }
      public Long getTimestamp() {
        return timestamp;
      }
      public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
      }
    }

    public static class NameBeanWrapper {
      final Bean bean;
      public NameBeanWrapper(Bean bean) {
        this.bean = bean;
      }
      @Override
      public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((bean == null || bean.name == null) ? 0 : bean.name.hashCode());
        return result;
      }
      @Override
      public boolean equals(Object obj) {
        if (this == obj) {
          return true;
        }
        if (obj == null) {
          return false;
        }
        if (getClass() != obj.getClass()) {
          return false;
        }
        NameBeanWrapper other = (NameBeanWrapper) obj;
        if (bean == null) {
          if (other.bean != null) {
            return false;
          }
        }else if (bean.name == null) {
            if (other.bean.name != null) {
              return false;
            }
        } else if (!bean.name.equals(other.bean.name)) {
          return false;
        }
        return true;
      }
    }

    public static class TimestampBeanWrapper {
      final Bean bean;
      public TimestampBeanWrapper(Bean bean) {
        this.bean = bean;
      }
      @Override
      public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((bean == null || bean.timestamp == null) ? 0 : bean.timestamp.hashCode());
        return result;
      }
      @Override
      public boolean equals(Object obj) {
        if (this == obj) {
          return true;
        }
        if (obj == null) {
          return false;
        }
        if (getClass() != obj.getClass()) {
          return false;
        }
        NameBeanWrapper other = (NameBeanWrapper) obj;
        if (bean == null) {
          if (other.bean != null) {
            return false;
          }
        }else if (bean.timestamp == null) {
            if (other.bean.timestamp != null) {
              return false;
            }
        } else if (!bean.timestamp.equals(other.bean.timestamp)) {
          return false;
        }
        return true;
      }
    }

  }

Upvotes: 1

Jordi Castilla
Jordi Castilla

Reputation: 27003

As suggested:

You want to have both lists of same object? Why don't create a parent object with all atributes you need and then implement two objects than inherit from first with different equals and hash?

Upvotes: 0

Eran
Eran

Reputation: 394126

What you are suggesting sounds like an abuse of the equals method and the Set interface.

Your use case defines two categories by which objects of a given type can be grouped (timestamp and name), and you wish to have two Sets, each holding at most a single instance for each category.

To do that, it would make more sense to have helper Sets :

Set<String> timestamps;
Set<String> names;

Then you can add names and timestamps to those sets, and use them to check if an object should be added to the target Collections (which don't have to be Sets).

For example :

List<SomeClass> timestampCategories = new ArrayList<SomeClass>();
List<SomeClass> nameCategories = new ArrayList<SomeClass>();
for (SomeClass object : inputCollection) {
    if (!timestamps.contains(object.getTimestamp()) {
        timestamps.add(object.getTimestamp());
        timestampCategories.add(object);
    }
    if (!names.contains(object.getName()) {
        names.add(object.getName());
        nameCategories.add(object);
    }
}

Upvotes: 1

Related Questions