List and Contains Method

I have this problem: starting from an empty list (0 items), I want to check if an item is in this list or not. If this entry is not in the list, I add this entry to the list, otherwise I update the item in the list. I tried to write this code:

program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Generics.Collections, System.Generics.Defaults; type TDBStats = record Comb: Integer; Freq: Integer; end; TDBStatsList = TList<TDBStats>; procedure Add(ODBStats: TDBStatsList; const Item: TDBStats); var rItem: TDBStats; begin rItem := Item; rItem.Freq := 1; oDBStats.Add(rItem); end; procedure Update(ODBStats: TDBStatsList; const Item: TDBStats; const Index: Integer); var rItem: TDBStats; begin rItem := Item; Inc(rItem.Freq); oDBStats[Index] := rItem; end; var oDBStats: TDBStatsList; rDBStats: TDBStats; myArr: array [0..4] of integer; iIndex1: Integer; begin try myArr[0] := 10; myArr[1] := 20; myArr[2] := 30; myArr[3] := 40; myArr[4] := 10; oDBStats := TList<TDBStats>.Create; try for iIndex1 := 0 to 4 do begin rDBStats.Comb := myArr[iIndex1]; if oDBStats.Contains(rDBStats) then Update(oDBStats, rDBStats, oDBStats.IndexOf(rDBStats)) else Add(oDBStats, rDBStats); end; // Check List for iIndex1 := 0 to Pred(oDBStats.Count) do Writeln(oDBStats[iIndex1].Comb:3, oDBStats[iIndex1].Freq:10); finally oDBStats.Free; end; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end. 

and should return this result:

 10 2 20 1 30 1 40 1 50 1 

but return this result:

 10 1 20 1 30 1 40 1 50 1 10 1 

I realized about the problem: when I use oDBStats.Contains (rDBStats), it controls if the rDBStats element is listed; The first time I did not find it and did not add it to the list; but when it is added to list i, update the freq field to 1; so the second time I check rdbstats again with freq = 0, did not find it. How can I solve this problem? I need to have a counter where I get a “comb” from the input, and I want to check if this “comb” is on the list, regardless of the value of another field in the record. In case I find a comb in the list, then I update by increasing the frequency field. Thanks for the help.

+3
delphi delphi-xe2
source share
2 answers

When you call Contains on a general list, it looks to see if the given value is inside the list. The value in your case is a record consisting of two fields. Since you did not specify a custom resolver, Delphi will use the default resolver, which compares the binary when writing. Thus, only if two entries are binary, they will be considered equal.

To make your work example, you must specify a custom mapper that only compares the row of row records. This is an example:

 oDBStats := TList<TDBStats>.Create(TDelegatedComparer<TDBStats>.Create( function(const Left, Right: TDBStats): Integer begin result := CompareValue(Left.comb, Right.comb); end)); 

In addition, you have an error in your upgrade procedure. Instead of increasing the existing value, you increase the undefined value of the item parameter. The change in the first line should make it work:

  rItem := oDBStats[Index]; Inc(rItem.Freq); oDBStats[Index] := rItem; 
+6
source share

You have the wrong data structure since you really need a dictionary .

The main problem with using a list is that you want to search on a subset of a saved record. But lists are not configured for this. Solve the problem by re-writing with TDictionary<Integer, Integer> .

I can recommend you carefully read the dictionary example in the Embarcadero docwiki docs .

The key to the dictionary is what you call comb , and the value is freq . To add an item, you do this:

 if Dict.TryGetValue(Comb, Freq) then Dict[Comb] := Freq+1 else Dict.Add(Comb, 1); 

I assume your dictionary is declared as follows:

 var Dict: TDictionary<Integer, Integer>; 

and is created as follows:

 Dict := TDictionary<Integer, Integer>; 

You can list the dictionary with a simple for in loop.

 var Item: TPair<Integer, Integer>; ... for Item in Dict do Writeln(Item.Key:3, Item.Value:10); 

Although it should be warned that the dictionary will be listed in odd order. You can sort before printing.

If you want to store additional information associated with each entry in the dictionary, put additional fields in the entry.

 type TDictValue = record Freq: Integer; Field1: string; Field2: TDateTime; //etc. end; 

Then your dictionary will become TDictionary<Integer, TDictValue> .

+1
source share

All Articles