Monday, April 11, 2011

How do I enumerate JvMemoryData...Or, how do I create a hash with a single key and multiple values?

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.

From stackoverflow
  • 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>
    
    Mick : I'll look into that. That sounds like exactly what I want.
    Mason Wheeler : Yeah, if you've got D2009, you can do this as a TDictionary or TObjectDictionary.
  • 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

  • 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.

    Mick : I hadn't seen that, very nice.
  • 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);
    

0 comments:

Post a Comment

Note: Only a member of this blog may post a comment.