I'm new to Delphi 5 and looking for a container (ideally a built-in one) that will do the same job as map
does in C++ (i.e. a sorted dictionary). I've done a preliminary Google search but nothing obvious seems to be suggesting itself. Please can anyone point me in the right direction?

- 20,238
- 4
- 51
- 80
-
3You may be new to Delphi 5, but Delphi 5 is not new to this world. It dates from the 20th Century. You can get 3rd party add-ons but all the good ones rely on the generics features introduced in D2009. – David Heffernan Aug 12 '11 at 13:49
-
@David: I'm unfortunately not at liberty to choose something more modern in this case -- but I'm aware that it's not new. – Stuart Golodetz Aug 12 '11 at 13:59
-
My instincts are that you will struggle to find something that works well in D5, but I could be proved wrong. – David Heffernan Aug 12 '11 at 14:03
-
What about IniFiles.THashedStringList? Is this included in D5? It only supports `string` keys and objects as value, but if that's what you need... – Heinrich Ulbricht Aug 12 '11 at 14:16
-
1@Heinrich Not included in D5 (but it is in D6 IIRC). It's performance is dire in any case which may not actually matter of course. – David Heffernan Aug 12 '11 at 14:26
-
THashedStringList was introduced in Delphi 6. – Bruce McGee Aug 12 '11 at 14:29
-
1I just looked it up. Delphi 5 is _12 years old_! Sounds like no fun if you are used to the new stuff. – Heinrich Ulbricht Aug 12 '11 at 14:30
-
@Heinrich: It's oddly interesting actually :) Looks like I may be writing my own map container though in this case. – Stuart Golodetz Aug 12 '11 at 14:35
-
@Stuart: Well I hope the "interest" lasts as long as your project ;) There are certainly already libs out there. Maybe you could make one run under D5 to spare you having to write one on your own. – Heinrich Ulbricht Aug 12 '11 at 14:39
-
1TStrings / TStringlist can be sorted and hold objects ... – mjn Aug 12 '11 at 15:19
-
@Heinrich: it's fine really. I still use D5 for a couple of apps as I didn't upgrade the db components used to D6 and the vendor seems to have stopped development a couple of years ago... And it helps a lot when you install GExperts so you can tweak the shortcuts to match what you use in your day job... (D2006/D2009/2010). Apart from language additions you can sort of backport almost anything. – Marjan Venema Aug 12 '11 at 16:41
-
Delphi 5 has some very annoyning issues (like the buggy `array of const`), even when it comes with "standard" language. Also the Variants is lacking Int64 and has some implementation missing points in comparison to Delphi 6, the SysUtils.pas unit lack of some basic functions, and so on... But you can still do wonders with Delphi 5... :) – Arnaud Bouchez Aug 13 '11 at 17:52
-
1If you want a typesafe solution, which I highly recommend - using existing containers and hard-casting can lead to nasty bugs - there used to be a slightly hacky method for **implementing generics on old versions of Delphi** (pre-2009, including Delphi 5.) This could be your best bet. I put it in my answer below. – David Aug 15 '11 at 01:53
-
@David I don't get your " existing containers and hard-casting " thing. Do you mean TList using TObject? There are other more powerful solutions, even for Delphi 5. See my answer. – Arnaud Bouchez Aug 15 '11 at 18:38
-
@Arnaud - yes. If you use TList with TObject, TStringList, etc... all of them require you to cast from TObject either to a TObject descendant or (worse, and it depends what Stuart wants to place in his container) strings, integers, etc. Horrible and bug-prone. Your answer using RTTI is very clever though, it's a very "Delphi" solution! – David Aug 15 '11 at 23:47
-
@David You're right: mapping `TObject` can be error-prone. But you can make your code a bit "stronger", e.g. by using `if not Sender.InheritsFrom(TMyClass) then exit;` or `(Objects[] as TMyClass)`. The VCL uses the `Sender: TObject` parameters in every event handler, and if it's properly used, it can be safe. But like with pointers, you have to know a little bit about what you are doing. – Arnaud Bouchez Aug 16 '11 at 05:59
4 Answers
Take a look at our TDynArray
wrapper.
It's a wrapper around any existing dynamic array (including dynamic array of records), which will add TList
-like methods to the dynamic array. With even more features, like search, sorting, hashing, and binary serialization. You can set the array capacity with an external Count
variable, so that insertion will be much faster.
type
TGroup: array of integer;
var
Group: TGroup;
GroupA: TDynArray;
i, v: integer;
Test: RawByteString;
begin
GroupA.Init(TypeInfo(TGroup),Group); // associate GroupA with Group
for i := 0 to 1000 do begin
v := i+1000; // need argument passed as a const variable
GroupA.Add(v);
end;
v := 1500;
if GroupA.IndexOf(v)<0 then // search by content
ShowMessage('Error: 1500 not found!');
for i := GroupA.Count-1 downto 0 do
if i and 3=0 then
GroupA.Delete(i); // delete integer at index i
Test := GroupA.SaveTo; // serialization into Test
GroupA.Clear;
GroupA.LoadFrom(Test);
GroupA.Compare := SortDynArrayInteger;
GroupA.Sort; // will sort the dynamic array according to the Compare function
for i := 1 to GroupA.Count-1 do
if Group[i]<Group[i-1] then
ShowMessage('Error: unsorted!');
v := 1500;
if GroupA.Find(v)<0 then // fast binary search
ShowMessage('Error: 1500 not found!');
This example uses an array of integer, but you may use it with an array of records, even containing strings, nested dynamic arrays, or other records.
Works from Delphi 5 up to XE.
I find it even easier to use than generics (e.g. for the auto-serialization feature). ;)
See http://blog.synopse.info/post/2011/03/12/TDynArray-and-Record-compare/load/save-using-fast-RTTI

- 42,305
- 3
- 71
- 159
Well if D5 doesn't contain THashedStringList
then maybe this one (from OmniThreadLibrary) does the job:
https://github.com/gabr42/OmniThreadLibrary/blob/master/src/GpStringHash.pas
I cite:
Tested with Delphi 2007. Should work with older versions, too.
Well, your version is definitely older :)

- 5,414
- 26
- 38

- 10,064
- 4
- 54
- 85
This can be accomplished 'out of the box' in D5 using TList.Sort or TObjectList.Sort - in your case you'd probably want to implement a class along the lines of:
TMyClass
public
Index:integer;
Value:TWhatever;
...
end;
To store in your list, then implement TList.Sort or TObjectList.Sort using your index value for sorting. It will take a bit of work but not terrible. See the D5 help on these classes for implementation details.
Unfortunately there are no generics in D5 so you'll probably have to to a lot of type casting or develop redundant container classes for different types.

- 10,879
- 12
- 61
- 101
This brings back memories. There is another interesting technique that's suitable for ancient versions of Delphi like yours. Read on!
From your description you sound like you want a fairly generic container - ie, one you can use with a variety of types. This cries out for generics (yes, use a new Delphi!) But back in the old days, there used to be a slightly hacky way to implement templates / generics with Delphi pre-2009, using a series of define
s and include
s. It took a bit of googling, but here's an article on these 'generics' that's much like what I remember. It's from 2001; in those days Delphi 5 was still recent-ish.
The rough idea is this: write a class to do what you want (here, a map from key to value) for a type, and get it working. Then change that file to use a specific name for the type (TMyType
, anything really) and strip the file so it's no longer a valid unit, but contains code only. (I think two partial files, actually: one for the interface
section, one for implementation
.) Include the contents of the file using {$include ...}
, so your whole Pascal file is compiled using your definitions and then the contents of the other partial included files which uses those definitions. Neat, hacky, ugly? I don't know, but it works :)
The example article creates a typed object list (ie, a list not of TObject
but TMemo
, TButton
, etc.) You end up with a file that looks like this (copied from the linked article):
unit u_MemoList;
interface
uses
Sysutils,
Classes,
Contnrs,
StdCtrls;
{$define TYPED_OBJECT_LIST_TEMPLATE}
type
_TYPED_OBJECT_LIST_ITEM_ = TMemo;
{$INCLUDE 't_TypedObjectList.tpl'}
type
TMemoList = class(_TYPED_OBJECT_LIST_)
end;
implementation
{$INCLUDE 't_TypedObjectList.tpl'}
end.
You will need to write your own map-like class, although you should be able to base it on this class. I remember that there used to be a set of 'generic' containers floating around the web which may have used this technique, and I would guess map is among them. I'm afraid I don't know where it is or who it was by, and Googling for this kind of thing shows lots of results for modern versions of Delphi. Writing your own might be best.
Edit: I found the same article (same text & content) but better formatted on the Embarcadero Developer Network site.
Good luck!

- 13,360
- 7
- 66
- 130
-
1Sounds like a pretty awful trick, IMHO. Resulting code is a mess, and you'll need one unit per type! And Delphi IDE just is buggy with include files (at least Delphi 5-2007). – Arnaud Bouchez Aug 15 '11 at 18:39
-
@Arnaud - awful? It would be hard to fix, you need to know your containers work before modifying them like this. But for its time I think it was very clever. I never used this technique, but I remember it being around and on Delphi forums etc a decade ago - I thought Stuart would be interested since it's one solution from that period applicable to his version of Delphi. Include files - yeah. In fact FPC used them (last I looked) all over the place - made the code really hard to follow. – David Aug 15 '11 at 23:49
-
@David FPC does like include files, whereas Delphi just fails handling them, as soon as there are more complex than a few conditionals. For instance, it's years that the Delphi compiler is not able to compile FPC (yes - it used to!), because it just hangs on included files. And the Delphi IDE parser is even worse. – Arnaud Bouchez Aug 16 '11 at 05:50
-
This article presents some sort of "generic of the poor", trying to map c++ templates with Delphi - which lacks of a pre-processor. IMHO such an attempt is a failure from the beginning, because Delphi does not have a real pre-processor (and I don't think it's a shame, since pre-processing is one of the root cause of C/C++ complexity - macros in C can be very powerful, but could be awful to debug - Delphi `inline` is much cleaner IMHO). I would have found it much cleaner to create some external code generator. – Arnaud Bouchez Aug 16 '11 at 05:53
-
1@Arnaud: you really truly absolutely don't like this, do you :) I'm not arguing it's *great* - I think the best thing would be to use Delphi XE(2) and modern containers and genuine templates. I would never use this code now, of course!! (And in fact I never have done, either, although if I was stuck with D5 these days, being used to templates and typed containers and stuff, I'd consider it.) It's a hack, and it's ugly code. But: it will give a typesafe container in an ancient version of Delphi, that's all - I think that's good :) – David Aug 16 '11 at 08:04