Reputation: 1000
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
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
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
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
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