- Home /
Map/Dict of Arrays
Hello, I come from a prior Javascript + Python background and I'm having some trouble editing a dictionary. I'm using strings for the keys and arrays for the values. I understand Unity's Javascript implementation isn't completely the same thing, but I've been stuck on this for a while and would like some help. Here's an example in Javascript of what I'd like to do:
var x = {}
x['1'] = ['one', 'uno'];
x['2'] = ['two'];
x['2'].push('dos');
I get a compile error on the push operation since it does not recognize the object as an array.
It seems like x is created as a Hastable object with x['2'] being a DictionaryEntry object. It feels like DictionaryEntry objects aren't meant to be mutable...that or I'm doing something very wrong. If it is the case that they aren't meant to be mutable, does anyone have any suggestions on how to create a dictionary that I can alter dynamically? Thanks in advance!
Answer by whydoidoit · Apr 14, 2013 at 08:31 AM
So, like you say, the problem is that Unity Script isn't Javascript - they've tried to make some things look the same, but dictionaries are a different matter.
You want to use native arrays with defined types or Lists if you want the size to be mutable, so what you are after is:
import System.Collections.Generic;
var myDictionary = new Dictionary.<String, List.<String>>();
Now no problem to access the entries if they existed:
x["2"].Add("dos");
print(x["1"][0]);
However the List. will not have been initialized for new keys. To the first time:
if(!x.ContainsKey("2")) x["2"] = new List.<String>();
I find this annoying all the time :) So I've written a C# override to dictionary that handles the initialization. You can use this from JavaScript if you put the C# in Plugins and don't use it in a JavaScript Plugin.
Index.cs
using System;
using System.Collections.Generic;
public class DefaultDictionary<TK, TR> : Dictionary<TK, TR>
{
public new virtual TR this[TK index]
{
get
{
if (ContainsKey(index))
{
return base[index];
}
return default(TR);
}
set
{
base[index] = value;
}
}
public T Get<T>(TK index) where T : TR
{
return (T)this[index];
}
}
public class Index<TK, TR> : DefaultDictionary<TK, TR> where TR : new()
{
public virtual TR Create()
{
return new TR();
}
public override TR this[TK index]
{
get
{
TR value;
if (TryGetValue(index, out value))
{
return value;
}
var ret = Create();
base[index] = ret;
return ret;
}
set
{
base[index] = value;
}
}
}
You use this by defining an:
var x = new Index.<String, List.<String>>();
This you can use without initializing anything yourself:
x["Whatever"].Add("It doesn't matter");
print(x["Whatever"][0]);
The default dictionary is useful when it's a value type or you want a null rather than an exception if the dictionary doesn't have the key:
var d = new DefaultDictionary.<String, boolean>();
print(d["someMissingKey"]); //Prints false rather than throwing an exception
Thanks for the awesome reply whydoidoit! It seems like I need to look a bit more into what bits of $$anonymous$$ono is revealed through UnityScript and throw away a lot of preconceptions.
As a note to anyone that tries whydoidoit's code in Javascript, you need to add a space at the end of the List type within the Dictionary initialization:
var myDictionary = new Dictionary.<String, List.<String>>();
to
var myDictionary = new Dictionary.<String, List.<String> >();
Figured it out from here:
Ah good point :) Yeah that'll do me for program$$anonymous$$g in an Answer box ;)
Really you need to forget all the clever stuff you know about Javascript - because most of it either won't work, won't quite work or will work but be poor perfor$$anonymous$$g. Then there's all the extra stuff like defining classes etc etc - really a bunch of stuff to learn.
I'd be program$$anonymous$$g JS for 6 months before starting with Unity, but my background is C# and I switched back to that eventually.