- Home /
Array or Data Structure with Vector3 as keys
Is it possible to set up an array or data structure of some kind where the keys are vector3's?
How would that be helpful? They're three floating point numbers!
Hmm... suppose you have just one gameobject in each discrete coordinate, and you want to reference the one at a particular coordinate...
It seems obvious why this would be helpful. This is why people use hashtables and dictionaries all the time.
The coordinates are not "discrete" if they're represented by floating point numbers. You should describe the application for which you've come to this convoluted solution.
Answer by petrucio · Jul 17, 2015 at 07:15 AM
You can't use Vector3 as keys directly, since the hash will be generated from the object itself, not it's contents, which is what you want.
I've made an extension that returns a unique int from a vector. I'm my case I only need to know it's discrete integer values, and I assume they will never be larger than 1000. You can change it to suit your needs if needed, but the gist will be the same.
//=========================================================================
// Rounds coordinates to integers, and returns an int that can easily be hashed and used as a key
// Assumes coordinates will never be greater than 1000 in any direction
public static int HashableInt(this Vector3 vector)
{
int x = Mathf.RoundToInt(vector.x);
int y = Mathf.RoundToInt(vector.y);
int z = Mathf.RoundToInt(vector.z);
return x * 1000 + z + y * 1000000;
}
Also, this doesn't work if the objects are closer than 1 unity from each other. In any other case, it's a perfectly valid way to do it.
And it will also go wrong with, say... x:1, y:0, z:-500
which produces the same hash as: x:0, y:0, z:500
This answer is actually wrong. You can use a Vector3 directly as a key in a dictionary. The GetHashCode method of Vector3 looks like this:
public override int GetHashCode()
{
return this.x.GetHashCode() ^ this.y.GetHashCode() << 2 ^ this.z.GetHashCode() >> 2;
}
Which is a quite strong hash. The hash for y and z are shifted 2 bits so they don't cancel each other out when they have the same value(s). Of course the Vector3 has to hold an exact value. The slightest error will result in a different hash. So "23.12345f" is not the same as 23.12346f.
The hash created in this answer is very weak it only works for a quite limited range. If you use a dictionary and you want to use a 3 component vector for whole numbers you should create your own struct and implement GetHashCode the same way Unity did for Vector3. I once created a "Vector3i" struct for exactly this purpose. It's basically the same struct but it uses ints ins$$anonymous$$d of floats.
Answer by jahroy · Jan 20, 2012 at 06:03 PM
You could use a hashtable or a dictionary:
var objectArray : GameObject [];
/* example using a hashtable */
var vectorHash : Hashtable = new Hashtable();
/* create hashtable to lookup gameobjects by their position */
for ( var thisObject : GameObject in objectArray ) {
var theVect : Vector3 = thisObject.transorm.position;
vectorHash[theVect] = thisObject;
}
/* example using a dictionary */
var vectorTable : Dictionary.<Vector3, GameObject> =
new Dictionary.<Vector3, GameObject> ();
for ( var thisObject : GameObject in objectArray ) {
var theVect : Vector3 = thisObject.transorm.position;
vectorTable[theVect] = thisObject;
}