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