how hash_t toHash() works?
Ivan Kazmenko
gassa at mail.ru
Sun Apr 28 06:18:03 PDT 2013
Hi,
> I have a class which I want to use as key in an assoc array like
> this:
>
> string["KeyString"] myArray;
>
> What i want is to preserve the order in the array. I want always
> to have "1" before "2" if the string is a numeric value.
>
> Can anyone help me to understand how const hash_t toHash()
> should
> work?
Associative arrays in D are implemented as hash tables. Hashing
sacrifices ordering capabilities for greater speed. Creating a
hash table will most certainly take your toHash value modulo some
integer you can not control (small for small tables, large for
larger ones). It would be crippling, if at all possible, to have
foreach on an associative array always produce a sorted result.
I'd suggest using std.container.RedBlackTree instead. It doesn't
provide syntactic sugar (like "container[key] = value") but
preserves the ordering.
Also note that sorting items as strings should be separated from
sorting as integers. For example, a value convertible to integer
should be always less (or always greater) than a non-convertible
value. Otherwise, it would quickly lead to inconsistent
comparisons, as in "22" <s "22a" <s "4" <n "22". Here, "<s"
compares values as strings and "<n" as integers.
Below is an example of using RedBlackTree close to what you might
need:
-----
import std.container;
import std.conv;
import std.stdio;
bool doConv(out long val, string s) {
try {
val = to!long(s);
return true;
}
catch(ConvException) {
return false;
}
}
struct KeyString {
string str;
KeyString opAssign(string val) {
str = val;
return this;
}
const int opCmp(ref const KeyString s) {
long v1, v2;
auto b1 = doConv(v1, str);
auto b2 = doConv(v2, s.str);
if (b1 != b2) return b2 - b1;
if (b1 && b2) return (v1 > v2) - (v1 < v2);
return std.string.cmp(str, s.str);
}
}
struct MyRecord {
KeyString key;
int val;
this(string nkey, int nval) {
key = nkey;
val = nval;
}
}
void main () {
auto cont = redBlackTree !("a.key < b.key", true, MyRecord) ();
cont.insert(MyRecord("1", 1));
cont.insert(MyRecord("111", 2));
cont.insert(MyRecord("25", 3));
cont.insert(MyRecord("53", 4));
cont.insert(MyRecord("a", 5));
cont.insert(MyRecord(" ", 6));
cont.insert(MyRecord("1234567890123456789", 7));
cont.insert(MyRecord("12345678901234567890", 8));
foreach (ref const cur; cont) {
writefln("cont[\"%s\"] = %s", cur.key.str, cur.val);
}
}
-----
The example prints:
-----
cont["1"] = 1
cont["25"] = 3
cont["53"] = 4
cont["111"] = 2
cont["1234567890123456789"] = 7
cont[" "] = 6
cont["12345678901234567890"] = 8
cont["a"] = 5
-----
The last three entries are strings not convertible to a long, so
they are ordered lexicographically.
Ivan Kazmenko.
More information about the Digitalmars-d-learn
mailing list