I'm using a TreeMap (SortedMap) whose keys are Object[] with elements of varying types.
TreeMap's equals() doesn't work on Object[] like Arrays's equals() would do -- which means it won't work when using its methods like containsKey() and get() unless I workaround it.
Is there somewhere a solution for this that doesn't involve creating a whole new Class?
EDIT :
Just to make it clear, I made a mistaken assumption. Creating a new Comparator(){} also does affect every method that uses equality, such as equals(), not only the tree sorter.
Is there somewhere a solution for this that doesn't involve creating a whole new Class?
No. In fact, you shouldn't be using mutable values for map keys at all.
While I agree with Matt Ball that you generally shouldn't use mutable (changeable) types as your keys, it is possible to use a TreeMap in this manner as long as you are not planning on modifying the arrays once they are in the tree.
This solution does involve the creation of a class, but not a new Map class, which is what it seems you are asking. Instead, you would need to create your own class which implements Comparator<Object[]> that can compare arrays. The class could use the Arrays.equals() method to determine if they are equal, but would need to also have a consistent rule to determine which array comes before another array when the arrays are not equal.
Related
My program has to pass a lot of arrays between threads. I want a collection that can accept an array, and then a contains method will specify whether a Set/Map contains the array (i.e. it is a duplicate or has already been processed by the thread). I assume this collection would have to use Arrays.equals(a1, a2), because the Object.equals() method will not work on arrays. Is it possible to write a collection that works like this, or would it fail when autoboxing from, say, int[] to Integer[]?
Use a wrapper for Array which overrides hashCode() and equals() like Arrays.asList().
BTW, you should avoid using arrays and opt for Collections whenever possible. I also recommend you use immutable data structures for multi-threading. Using a mutable object in a Set or as the key of a Map is a terrible idea anyways.
I need a Java generic class to represent unordered pairs of any type. Meanwhile I see two solutions:
HashSet to store the pair elements
a Pair class with overriden hashCode and equals (to make Pair(a, b) and Pair(b, a) equal).
Does it make sense? What would you suggest?
In your place I would roll out my own class. As long as you are interested in sets of only two objects, using HashMap, HashSet (which, incidentally, uses a HashMap internally anyway) or any other class designed for sets of arbitrary cardinality is a waste of resources and adds unneeded complexity.
Just create your own class with proper equals() and hashCode() implementations. Having a contains() operation, or even implementing parts of the Set interface, might also make sense.
One important note: make sure you document your class extensively - at least specify whether equals() performs an identity or an equality comparison for the contained objects, and what is the meaning of a null contained reference...
I have a class Attribute which has 2 variables say int a,b;
I want to use class Attribute in two different HashSet.
The first hash set considers objects as equal when the value of a is same.
But the second hash set considers objects as equal when the value of b is same.
I know if I override the equals method the hashset will use the overriden version of equals to compare two objects but in this case I would need two different implementations of equals()
One way is to create two subclasses of attribute and provide them with different equals method but I want to know if there is a better way to do it such that I dont have to create subclass of Attribute.
Thanks.
One possible solution is to not use HashSet, but use TreeSet instead. It's the same Set interface, but there is a TreeSet constructor that lets you pass in a Comparator. That way you could leave the Attribute class unchanged- just create two different comparators and use it like
Set<Attribute> setA = new TreeSet<Attribute>(comparatorForA);
Set<Attribute> setB = new TreeSet<Attribute>(comparatorForB);
The comparator takes care of the equality check (e.g. if compare returns 0, the objects are equal)
Unfortunately there's no "Equalizer" class that can override the equals logic. There is such a thing for sorting, where you can either use natural sorting based on the Comparable implementation or provide your own Comparator. I've actually wondered why there's no such thing for equality checks.
Since the semantics of equality are defined by a class and could be considered a trait of that class, the two subclasses approach seems the most natural. Maybe someone knows a useful pattern for doing this in a more simple manner, but I've never encountered it.
EDIT: just thought of something... you could use two Map instances, like HashMap, with the first one using a as key and the second using b as key. It'd let you detect collisions. You could then simply link the attribute to the associated instance.
I did some thing different, Instead of using the HashSet, I have used HashMap where I have used int a as a key in first HashMap and the object is stored as value.
And in the other HashMap I have kept the key as int b and the object as value.
This provides me a way to Hash on both the variables a and b so I dont have to make any sub classes.
And also, I get O(1) time instead of O(log n). But I know I am paying the price by using some more memory but my main concern was time so I chose HashMap over TreeSet.
Thank you all for your comments and suggestions.
It would be very easy to modify HashMap and HashSet to accept hashing and equality-testing strategies.
public interface Hasher {
int hashCode(Object o);
}
public interface Equalizer {
int areEqual(Object o1, Object o2);
}
A simple solution is to bypass HashSet and use HashMap directly. For the first, store each Attribute using its a property as the key, and for the other use b.
I can propose a bit hacky but lesser effort solution :)
Swap the values of a and b when storing in second hashset so that uniqueness is defined by value of b and then when reading the class from hashset then swap the value of a and b again to retain the original state. So the same equals/hascode methods will serve the purpose.
I have a List which contains a list of objects and I want to remove from this list all the elements which have the same values in two of their attributes. I had though about doing something like this:
List<Class1> myList;
....
Set<Class1> mySet = new HashSet<Class1>();
mySet.addAll(myList);
and overriding hash method in Class1 so it returns a number which depends only in the attributes I want to consider.
The problem is that I need to do a different filtering in another part of the application so I can't override hash method in this way (I would need two different hash methods).
What's the most efficient way of doing this filtering without overriding hash method?
Thanks
Overriding hashCode and equals in Class1 (just to do this) is problematic. You end up with your class having an unnatural definition of equality, which may turn out to be other for other current and future uses of the class.
Review the Comparator interface and write a Comparator<Class1> implementation to compare instances of your Class1 based on your criteria; e.g. based on those two attributes. Then instantiate a TreeSet<Class>` for duplicate detection using the TreeSet(Comparator) constructor.
EDIT
Comparing this approach with #Tom Hawtin's approach:
The two approaches use roughly comparable space overall. The treeset's internal nodes roughly balance the hashset's array and the wrappers that support the custom equals / hash methods.
The wrapper + hashset approach is O(N) in time (assuming good hashing) versus O(NlogN) for the treeset approach. So that is the way to go if the input list is likely to be large.
The treeset approach wins in terms of the lines of code that need to be written.
Let your Class1 implements Comparable. Then use TreeSet as in your example (i.e. use addAll method).
As an alternative to what Roman said you can have a look at this SO question about filtering using Predicates. If you use Google Collections anyway this might be a good fit.
I would suggest introducing a class for the concept of the parts of Class1 that you want to consider significant in this context. Then use a HashSet or HashMap.
Sometimes programmers make things too complicated trying to use all the nice features of a language, and the answers to this question are an example. Overriding anything on the class is overkill. What you need is this:
class MyClass {
Object attr1;
Object attr2;
}
List<Class1> list;
Set<Class1> set=....
Set<MyClass> tempset = new HashSet<MyClass>;
for (Class1 c:list) {
MyClass myc = new MyClass();
myc.attr1 = c.attr1;
myc.attr2 = c.attr2;
if (!tempset.contains(myc)) {
tempset.add(myc);
set.add(c);
}
}
Feel free to fix up minor irregulairites. There will be some issues depending on what you mean by equality for the attributes (and obvious changes if the attributes are primitive). Sometimes we need to write code, not just use the builtin libraries.
Let's say I have a collection of objects which can be sorted using a number of different comparators based on the different fields of the object.
It would be nice to be able to know later on in the code which comparator was used to sort the Collection with and if it was ascending or descending. Is there anyway to do this elegantly instead of using a bunch of Booleans to keep track of things?
Not for the Collection interface, but if you use a SortedSet there's a comparator() method where you can ask for its comparator.
Otherwise you'll have to subclass the collection class you're using to add the accessors you need.
No there's nothing with the implementations that does this. You would need to track it yourself. You could subclass a Collection implementation to add fields which hold this information.
You could also map the implementations to metadata as you like with a Map -- in particular it seems like you want IdentityHashMap to do this, since you don't want two different collections to be compared for equality as keys with equals().
I would store a boolean (ascending/descending), and a reference to the Comparator used to sort, if that's what completely determines the sort. Or if it's sorted on field, store a String naming the field perhaps.
sure:
define methods for your decorated Collection<Foo>
public List<Comparator<Foo>> getComparators() { ... }
and
public int whichComparator() { ... }
that returns which Comparator is currently in use from the List. You could make it fancier with a Map and some sensible keys (say, enums - perhaps even enums which implement the comparators) if you're modifying which comparators might be used over the life of the object, but I think the above is a good enough start.