views:

393

answers:

4

I am using JvMemoryData to populate a JvDBUltimGrid. I'm primarily using this JvMemoryData as a data structure, because I am not aware of anything else that meets my needs.

I'm not working with a lot of data, but I do need a way to enumerate the records I am adding to JvMemoryData. Has anyone done this before? Would it be possible to somehow "query" this data using TSQLQuery?

Or, is there a better way to do this? I'm a bit naive when it comes to data structures, so maybe someone can point me in the right direction. What I really need is like a Dictionary/Hash, that allows for 1 key, and many values. Like so:

KEY1: val1;val2;val3;val4;val5;etc...
KEY2: val1;val2;val3;val4;val5;etc...

I considered using THashedStringList in the IniFiles unit, but it still suffers from the same problem in that it allows only 1 key to be associated with a value.

+1  A: 

I'm not a Delphi programmer but couldn't you just use a list or array as the value for each hash entry? In Java terminology:

Map<String,List>
jdigital
I'll look into that. That sounds like exactly what I want.
Mick
Yeah, if you've got D2009, you can do this as a TDictionary or TObjectDictionary.
Mason Wheeler
A: 

I have been using an array of any arbitrarily complex user defined record types as a cache in conjunction with a TStringList or THashedStringList. I access each record using a key. First I check the string list for a match. If no match, then I get the record from the database and put it in the array. I put its array index into the string list. Using the records I am working with, this is what my code looks like:

function TEmployeeCache.Read(sCode: String): TEmployeeData;
var iRecNo: Integer;
    oEmployee: TEmployee;
begin
  iRecNo := CInt(CodeList.Values[sCode]);
  if iRecNo = 0 then begin
    iRecNo := FNextRec;
    inc(FNextRec);
    if FNextRec > High(Cache)  then SetLength(Cache, FNextRec * 2);
    oEmployee := TEmployee.Create;
    oEmployee.Read(sCode);
    Cache[iRecNo] := oEmployee.Data;
    oEmployee.Free;
    KeyList.Add(Format('%s=%s', [CStr(Cache[iRecNo].hKey), IntToStr(iRecNo)]));
    CodeList.Add(Format('%s=%s', [sCode, IntToStr(iRecNo)]));
  end;
  Result := Cache[iRecNo];
end;

I have been getting seemingly instant access this way.

Jack

+1  A: 

You already seem to be using Jedi. Jedi contains classes that allow you to map anything with anything.

Take a look at this related question.

Lieven
I hadn't seen that, very nice.
Mick
+2  A: 

One way would be to create a TStringList, and have each item's object point to another TList (or TStringList) which would contain all of your values. If the topmost string list is sorted, then retrieval is just a binary search away.

To add items to your topmost list, use something like the following (SList = TStringList):

Id := SList.AddObject( Key1, tStringList.Create );
InnerList := tStringList(SList.Objects[id]);
// for each child in list
  InnerList.add( value );

When its time to dispose the list, make sure you free each of the inner lists also.

for i := 0 to SList.count-1 do
  begin
    if Assigned(SList.Objects[i]) then
      SList.Objects[i].free;
    SList.Objects[i] := nil;
  end;
FreeAndNil(SList);
skamradt