Java: Mapping array elements to a set of properties - java

I have multidimensional double[][] arrays of which each element has a set of properties.
I designed these properties as a Class:
public class ElemProperties
{
public double prop1;
...
}
Linking them with the elements of the array using a HashMap:
HashMap<double[][], ElemProperties> elemProperties;
using it like e.g:
elemProperties.get(exampleArray).getProp1();
However, this only serves as a mapping between the whole array and properties. What I'm trying to do is to actually map the elements. Since Java doesn't have pointers, I'm kind of stuck at this position. This design seems very convoluted is there a better way to achieve this goal?

First attempt would be:
public class Elem {
private double value;
private double additionalProperty1;
private double additionalProperty2;
...
}
And create an Elem[][] instead of a double[][].
This at least works but multi-dimensional arrays aren't too efficient and aren't too expressive either, so the next question is whether you could group them using a different structure.
If the additional properties are optional or could be shared between multiple elements, you would need to write objects for them too, but the starting point is the same.
It is of course possible that you genuinely need a Map to link values to additional properties "because of reasons". In that case you can do something like this:
public class Container {
private double[][] values;
private Map<Double,AdditionalProperties> properties;
public double getValue(int x, int y) {
return values[x][y];
}
public AdditionalProperties getProperties(int x, int y) {
return properties.get( getValue(x, y ) );
}
}
This way you can hide the fact that you use two separate data structures to store the data, and maintain data integrity between them.
Note though that this is semantically very different from the first solution. In particular, positions containing the same value will share their AdditionalProperties.
(There are also practical problems with this implementation, #dasblinkenlight already pointed out why using doubles as keys to a map is an issue, the other is that an autoboxing conversion happens and that can add some memory and run time overhead. All these problems can be overcome with careful coding, but I'm only demonstrating the basic concept here.)

since the HashMap compares for references this works.
Comparing for references also happens to be the biggest problem with this approach: the fact that the object is a 2d array of double does not matter - one could simply replace your map with
HashMap<Object,ElemProperties> elemProperties;
without losing any functionality.
A better approach would be making a class that represents 2D keys based on arrays of double:
class KeyDouble2D {
private final double[][] key;
public KeyDouble2D(double[][] key) {
// Make a copy of key into this.key
}
public boolean equals(Object other) {
// Ensure that other is KeyDouble2D, then compare key
// sizes, and finally compare arrays element-by-element.
// Make sure to use `Double.equals` method to avoid NaN != NaN problem.
}
public int hashCode() {
// Compute hash code as a sum of hash codes in 2D array
}
}
You can use this class for keys of your hash map:
HashMap<KeyDouble2D,ElemProperties> elemProperties = ...;
...
ElemProperties prop = elemProperties.get(new KeyDouble2D(exampleArray)).getProp1();
Note that one needs to be very careful when using arrays of double for hash keys, for the same reason why one needs to be careful when comparing doubles for equality.

Why not create a class DoubleWithProperties, and manipulate an array of this class, instead of using a hashmap?
class DoubleWithProperties {
double value;
ElemProperties props;
public DoubleWithProperties(double value, ElemProperties props){
...
}
}
DoubleWithProperties[][] array = new DoubleWithProperties[5][5];

Related

Association Object-Enum, which is more efficient?

Let's say I have the following enum:
public enum Example{
A,
B,
C,
D,
E;
}
I need an association between an Object and the enum above.
In my specific case, one object must have only one Example association, except for Example.B and Example.C, because an Object could eventually have these two associations.
Right now my solution is: I have created an object wrapper of a five booleans, each boolean representing an enum. When it's true it means there is an association with the represented Example constant.
In the end I have an association between the Object and the Wrapper.
The thing is that I believe it's unnecessary to carry around these five booleans, because in most cases only boolean will be true and in very few cases only two booleans will be true. But never more than two.
Then I thought that maybe an association between an Object and an ArrayList<Example> would be more appropriate. Or maybe even better an array Example[] of size 2.
What do you think?
Please, if you have any different suggestions let me know.
You may add a field of type Set to the class you like to associate with one or more Examples. Add those Example values to the set you like to associate your type with.
Code Example
public class MyObject {
public static MyObject createAssociatedWithBAndC() {
return new MyObject(Example.B, Example.C);
}
public static MyObject create(Example example) {
return new MyObject(example);
}
private final Set<Example> examples = new HashSet<>();
private MyObject(Example... examples) {
for (Example example : examples) {
this.examples.add(example);
}
}
}
And in case you really, really need to avoid using too much memory try it this way (reflecting your requirements) which uses null as associated with B and C:
public class MyObject {
private final Example example;
private MyObject(Example example) {
this.example = example;
}
public Set<Example> getExamples() {
return example == null
? EnumSet.of(Example.B, Example.C)
: EnumSet.of(example);
}
}
Now you hold only one or none Examples while none means: associated with B and C. And if instantiation the EnumSet is as well to expansive try:
public class MyObject {
private final Set<Example> examples;
private MyObject(Example example) {
this.example = example == null
? EnumSet.of(Example.B, Example.C)
: EnumSet.of(example);
}
public Set<Example> getExamples() {
return examples;
}
}
Which is the goal to have boolean values to transform them into Example enum values ?
This is better :
Then I thought that maybe an association between an Object and an
ArrayList would be more appropriate. Or maybe even better an
array Example[] of size 2.
However, array use has limitations.
An array that has a variable size as in your case is harder to manipulate as you have to remember how many elements are effectively contained in (generally with a integer value).
Besides, if the size of 2 always goes to 3, you have to change its declaration.
I would prefer a List implementation or a Set implementation as the enum are constant and unique values. You could use an EnumSet implementation.
You could instantiate them like that :
EnumSet<Example> examples = EnumSet.of(Example.A, Example.B);

Map which allows to provide the equals-comparator and the hashing function separately

While trying to model polynomials, in particular their multiplication, I run into the following problem. During the multiplication, the individual monomials of the two polynomials are multiplied and of course in can happen that I have (3x^2 y + 5x y^2) * (x + y). The result contains 3x^2 y^2 and 5 x^2 y^2, which I want to combine by addition right away.
Naturally I would like to use the part x^2 y^2 of the monomial as a key in a (hash) map to add up the different coefficients (3 and 5 in the example). But the monomial object as I envisage it should naturally also contain the coefficient, which should not be part of the map key.
Of course I could write equals/hashcode of the monomial object such that they ignore the coefficient. But this feels just so wrong, because mathematically a monomial clearly is only equal to another one if also the coefficients are equal.
Introducing a coefficient-free monomial object for intermediate operations does also not look right.
Instead of using the map, I could use a list and use a binary search with a dedicated comparator that ignores the coefficient.
Short of implementing a map which does not use the keys' equals/hashcode, but a dedicated one, are there any better ideas of how to fuse the monomials?
Since the JDK implementation of [Linked]HashMap does not permits you to override the equals/hashCode implementation, the only other ways are:
a wrapping object like this:
class A {
private final String fieldA; // equals/hashCode based on that field.
private final String fieldB; // equals/hashCode based on that field.
}
class B {
private A a;
public int hashCode() {return a.fieldA.hashCode();}
public boolean equals(Object o) {... the same ... }
}
Map<B, Value> map = new HashMap<B, Value>();
map.put(new B(new A("fieldA", "fieldB")), new Value(0));
Well, with more getters/constructors.
This can be annoying, and perhaps there exists some library (like Guava) that allows an equals/hashCode method to be given like you can give a Comparator to TreeMap.
You'll find below a sample implementation that point out what to do to decorate an existing map.
use a TreeMap with a specific Comparator. The other answer point it, but I'd say you'll need to correctly define a Comparator because this could lead to problems: if you compareTo method returns 0 when equality is reached, and 1 in other case, this means there is no natural ordering. You should try to find one, or use the wrapper object.
If you want to take the challenge, you can create a basic implementation using delegation/decoration over another HashMap (this could be another kind of map, like LinkedHashMap):
public class DelegatingHashMap<K,V> implements Map<K,V> {
private final BiPredicate<K,Object> equalsHandler;
private final IntFunction<K> hashCodeHandler;
private final Map<Wrapper<K>,V> impl = new HashMap<>();
public DelegatingHashMap(
BiPredicate<K,Object> equalsHandler,
IntFunction<K> hashCodeHandler
) {
this.equalsHandler = requireNonNull(equalsHandler, "equalsHandler");
this.hashCodeHandler= requireNonNull(hashCodeHandler, "hashCodeHandler");
}
public Object get(K key) {
Wrapper<K> wrap = new Wrapper<>(key);
return impl.get(wrap);
}
...
static class Wrapper<K2> {
private final K2 key;
private final BiPredicate<K> equalsHandler;
private final IntFunction<K> hashCodeHandler;
public int hashCode() {return hashCodeHandler.apply(key);}
public boolean equals(Object o) {
return equalsHandler.test(key, o);
}
}
}
And the code using the map:
DelegatingHashMap<String, Integer> map = new DelegatingHashMap<>(
(key, old) -> key.equalsIgnoreCase(Objects.toString(o, "")),
key -> key.toLowerCase().hashCode()
);
map.put("Foobar", 1);
map.put("foobar", 2);
System.out.println(map); // print {foobar: 2}
But perhaps the best (for the memory) would be to rewrite the HashMap to directly use the handler instead of a wrapper.
You could use a TreeMap with a custom comparator:
TreeMap(Comparator<? super K> comparator)
Constructs a new, empty tree map, ordered according to the given comparator.
(Source)
Consider using a TreeMap, which is a SortedMapand thus also a Map. You can provide a Comparator to its constructor. The sorted map will use that Comparator for sorting the map keys. But importantly, for your case, it will consuder keys to be equal if the Comparator returns 0. In your case that will require a Comparator that is not consustent with equals, which could cause you problems if you are not careful.
Another option is to introduce another class, which acts as an adaptor for a Mononomial and can be used as a map key having the properties you deserve.
I think it may be better to separate the monomial into 2 parts: the coefficient and the variable. That way you can use the variable part in your map as the key and the coefficient as the value (which can then up updated).
All this code should be implementation details inside a Polynomial object
I'm not sure why you think a coefficient-free monomial does not look right. You don't have to expose the object to the outside if you don't want. But it might be a nice way to have getters on your Polynomial to get the coefficients for each monomial.

Using Java's contains(Object) method for Collections (eg HashSet) without actually having the object

I recognise that sounds a bit mad but to explain what I mean:
I have a Collection (eg HashSet) containing several quite slow initialisation objects and I want to see if the Collection already contains a particular object. Let's use Vector3d as an example (I know that is not expensive to initialise).
So the Collection contains:
Vector3d(1,1,1)
Vector3d(2,1,1)
Vector3d(3,1,1)
And I want to ask the Collection the question "does the Collection contain a Vector3d with x=2, y=1 and z=1 (i.e. I already know the data the .contains() method would hash against). So I could create a new Vector3d(2,1,1) and then use .contains() on that but as I said the objects initialisation is slow, or I could run through the entire Collection manually checking (which is what I'm doing now) but thats (as I understand it) slower than .contains() since it doesn't use hash. Is there a better way to do this?
The objects in question are mutable but the data that the equals method is based upon is not. (In my case they are blocks at x,y,z co-ordinates, the contents of the blocks may change but the x,y,z co-ordinates will not)
ArrayList is the correct data structure if you only need to iterate through all of your elements or access your elements by position. It is the wrong data structure for anything else.
What you are trying to do is answer the containment question quickly, which is what Sets and Maps are for. It would make much more sense to create a separate, cheaper Vector3dKey class with the simple hash function you want and insert your expensive objects into a Map< Vector3dKey, Vector3d > at the same time as, or instead of, an ArrayList< Vector3d >. Java obviously won't keep two copies of your expensive vectors, just copies of the references. Of course, this whole scheme breaks down if your Vectors are mutable.
Using the .contains() method on an ArrayList will result in the equals method being invoked against each and every instance in the ArrayList.
While that will work for you, it may not prove beneficial for extremely large ArrayLists. If performance is a problem, you may wish to hold a HashSet containing references to the Vector3d objects. Invoking contains on a HashSet (or any Set) is drastically faster.
If you REALLY have to use a list (and not a hash) you might as well iterate over the list, retrieve each object and check it's attributes manually--I mean that will be pretty much as quick as "Contains".
If you were going to use a hash instead of a list then you should use a different object for comparison. For instance, if you use a HashMap with your above example your keys could be the following strings:
"1,1,1","2,1,1","3,1,1"
This would make a lookup instant and easy. If the list could contain other types of objects, maybe "Vector3d(1,1,1)" would be a better string. It's easy to re-create without being expensive or adding code complexity.
If you were using a list because you needed to retain order, look at LinkedHashMap.
Also I suggest you create a function to derive the string from the object (when inserting) or from the parameters (when searching) rather than distributing the functionality around your code, this is the kind of thing you are likely to need to change or expand on later.
Code based on Judge Mental's answer
package mygame;
import java.util.HashMap;
import java.util.Map;
public class Main{
public Main(){
Map<CheapKey,ExpensiveClass> map=new HashMap< CheapKey, ExpensiveClass>();
for(int i=0;i<100;i++){
ExpensiveClass newExpensiveClass;
newExpensiveClass=new ExpensiveClass(i,0,0);
map.put(newExpensiveClass.getKey(), newExpensiveClass);
}
CheapKey testKey1=new CheapKey(1,0,0);
CheapKey testKey2=new CheapKey(1,0,1);
System.out.println(map.containsKey(testKey1)); //there is an object under key1
System.out.println(map.containsKey(testKey2)); //there isn't an object under key2
ExpensiveClass retrievedExpensiveClass=map.get(testKey1);
}
public static void main(String[] args) {
Main main=new Main();
}
protected class ExpensiveClass{
int x;
int y;
int z;
public ExpensiveClass(int x, int y, int z){
this.x=x;
this.y=y;
this.z=z;
for(int i=0;i<10000;i++){
//slow initilisation
}
}
public CheapKey getKey(){
return new CheapKey(x,y,z);
}
}
protected class CheapKey{
int x;
int y;
int z;
public CheapKey(int x, int y, int z){
this.x=x;
this.y=y;
this.z=z;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final CheapKey other = (CheapKey) obj;
return true;
}
#Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + this.x;
hash = 79 * hash + this.y;
hash = 79 * hash + this.z;
return hash;
}
}
}
The contains method will invoke the .equals method of an object, so as long as the implementation of .equals for that class compares the values contains in the objects not their pointers then using contains will work.
http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html#contains(java.lang.Object)
Edit misread your question a bit. I think it comes down to how big the list is vs how long the initialisation takes. If the list is short, iterate through it and manually check. However if the list is likely to be long, creating the objects and using .contains could well be more efficient.
ArrayList.contains doesn't use hashing; it's exactly the same speed as the manual check. It makes no difference either way.
Using a fake object class is doable, but almost certainly a code smell.

What's the fastest Java collection for single threaded Contains(Point(x,y)) functionality?

In my application I need to check a collection of 2D coordinates (x,y) to see if a given coordinate is in the collection, it needs to be as fast as possible and it will only be accessed from one thread.
( It's for collision checking )
Can someone give me a push in the right direction?
The absolute fastest I can think of would be to maintain a 2D matrix of those points:
//just once
int[][] occurrences = new int[X_MAX][Y_MAX];
for (Point p : points ) {
occurrences[p.x][p.y]++;
}
//sometime later
if ( occurrences[x][y] != 0 ) {
//contains Point(x, y)
}
If you don't care how many there are, just a boolean matrix would work. Clearly this would only be fast if the matrix was created just once, and maybe updated as Points are added to the collection.
In short, the basic Collections aren't perfect for this (though a HashSet would come close).
Edit
This could be easily adapted to be a Set<Point> if you don't find a library that does this for you already. Something like this:
public class PointSet implements Set<Point> {
private final boolean[][] data;
public PointSet(int xSize, int ySize) {
data = new boolean[xSize][ySize];
}
#Override
public boolean add(Point e) {
boolean hadIt = data[e.x][e.y];
data[e.x][e.y] = true;
return hadIt;
}
#Override
public boolean contains(Object o) {
Point p = (Point) o;
return data[p.x][p.y];
}
//...other methods of Set<Point>...
}
I would go using some Trove collections data structures.
If your points are stored as a couple of int or a couple of float you can pack them in a long: 32 bits for x-coord and 32 bits for y-coord. Then you can use a TLongHashSet that is an HashSet optimized for working with primitive data (it will be faster and consume less memory compared to normal java collections).
If you have int coordinates it would be something like
static private long computeKey(int h1, int h2)
{
return ((long)h1) << 32 | h2;
}
to compute the key and then use it
TLongHashSet set = new TLongHashSet()
set.add(long v);
set.addAll(long[] v);
set.containsAll(..);
if you have float values you can do the same thing, but you have to pack float bits inside the long.
HashSet. Its O(1) average. If you want true O(1) you can make a wrapper for your object which has a reference to a collection. That way you cant just compare it with the collection you have.
How often do you have to update the collection in comparison to searching it? You should chose an appropriate data structure based on that.
Point2D implements comparable, right? Then your best bet is probably a TreeSet, they are incredibly fast and I believe they rely on B+ trees, which you may know are used in actual databases and filesystems.
If you think you're going to be doing a fair amount of updates to the structure, take a look at the SkipList. It guarentees O(log(operations)) **NOTE this is for ALL operations you do, there is no guarentee about the runtime of a single opperation)
You can try some sort of sorted set, like treeset, since you can do binary searches on it.

Arrays of different types

Is it possible to have an array that contains two different types of data? I want to have an array that contains a double and also a string. I attempted:
ArrayList<double><String> array;
But that didn't work.
Sorry for the silly question, but it has been a while since I have used something like this.. Can you refresh my memory on how would I declare and populate such an array?
And then to take it a step further, I would like to sort the array by the double if possible?
Thanks!
Firstly, it's worth being clear about the difference between an array and an ArrayList - they're not the same thing at all.
However, in either case you can't do what you want. The closest you can probably come is declaring your own type. (EDIT: My original code had a double or a string... I've now changed it to be a double and a string. Let me know if this change isn't what you had in mind.)
public final class DoubleAndString
{
private final String stringValue;
private final double doubleValue;
public DoubleAndString(String stringValue, double doubleValue)
{
this.stringValue = stringValue;
this.doubleValue = doubleValue;
}
public String getString()
{
return stringValue;
}
public String getDouble()
{
return doubleValue;
}
}
Then create an ArrayList<DoubleAndString> or a DoubleAndString[].
Now, this feels somewhat vanilla at the moment - presumably the double and string values actually have a greater meaning - a name and a score, for example. If so, encapsulate that in a type which describes the pairing more appropriately.
As for ordering - you could make DoubleAndString implement Comparable<DoubleAndString> - but unless that's the only natural ordering which makes sense, I'd write a Comparator<DoubleAndString>:
public class DoubleComparator implements Comparator<DoubleAndString>
{
public int compare(DoubleAndString ds1, DoubleAndString ds2)
{
return Double.compare(ds1.getDouble(), ds2.getDouble());
}
}
Then you can use Collections.sort to sort an ArrayList<DoubleAndString> or Arrays.sort to sort an array.
You can use ArrayList<Object> and you can then use anything you'd like. Encapsulate the double in a Double object and when you retrieve the object use instanceof to check if it's really a double or a String.
I must say, it's unlikely this 'design' would win you any awards. Is it possible to rethink the solution you're considering for your problem, and see if you could do with a different kind of approach?
It sounds like you want a Map. Since you wish to sort the Map, a TreeMap may be optimal.
Map<Double, String> myMap = new TreeMap<Double, String>();
Maps are associative. Each double has an associated string. If you want multiple strings per double, you can use a
Map<Double, ArrayList<String>>
You might already know this, but it is not certainly not a good idea to store different types in a list. By definition an array is a collection of similar objects and stuffing all kinds in it makes things fuzzy. So really you would rather have a separate type to hold these different values.
Well, if you want to have an array with an arbitrary number of elements, then you simply need to use a type that is a common ancestor to both. In this case, that would be Object (since String and Double both inherit from Object). This will require you to check the types, though, when you retrieve or use them.
If you are using a fixed number of multiple different types, then what you really want is a "tuple". However, Java currently does not have an implementation of tuple available. For two items:
public class Pair<T1,T2>
{
public Pair(){
this(null,null);
}
public Pair(T1 x1){
this(x1,null);
}
public Pair(T1 x1, T2 x2){
_x1 = x1;
_x2 = x2;
}
public T1 getFirst(){
return _x1;
}
public T1 getSecond(){
return _x2;
}
private T1 _x1;
private T2 _x2;
}
You can just do ArrayList<object> arraylist and then you can put anything in it, but that may not be what you want.
Then, to sort you would just use your own comparator but, as theatrus mentioned, are these two values supposed to be connected, or do you have a single-dimension array with two different data types?
An ArrayList by definition only contains one object per position. You could do something like this:
List<MyTuple> list = new ArrayList<MyTuple>();
public static class MyTuple implements Comparable<MyTuple> {
private Double doubleValue;
private String stringValue;
//getters and setters
public int compareTo(MyTuple tuple) {
return doubleValue.compareTo(tuple.getDoubleValue());
}
}
You can then use the Collections.sort() method to sort it by the Doubles.
What do you want to do?
If it is not a key value mapping, you should create a new class for this.
You may want to look at the Number base class.
List<Number> list = new ArrayList<Number>();
list.add(new Integer(3));
list.add(new Double(5.2));
You may interpret the numbers as strings, using NumberFormat:
NumberFormat formatter = new DecimalFormat("#.##");
String s = formatter.format(list.get(0));
Though this may not be what you want, you are a bit short on details about your end goal.
if you are basically not trying to do any comparisons/sorting on the ArrayList then you could create something as below:
List list = new ArrayList();
otherwise.. Jon Skeet's answer was best approach.

Categories

Resources