Advertisement
Guest User

Untitled

a guest
Mar 16th, 2021
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 12.81 KB | None | 0 0
  1. program Project1;
  2.  
  3. {$APPTYPE CONSOLE}
  4.  
  5. {$R *.res}
  6.  
  7. uses
  8.   System.SysUtils, System.Generics.Collections, System.Math, System.Diagnostics, System.Generics.Defaults,
  9.   SynCommons;
  10.  
  11. type
  12.   TDataLine = class
  13.     SeqNo: integer;
  14.     TransactionID: integer;
  15.     CustomName: string;
  16.   end;
  17.   TDataLineArray = array of TDataLine;
  18.  
  19.   TDataLookup = class
  20.   var
  21.     fData: TObjectList<TDataLine>;
  22.  
  23.     fDataByID: TDictionary<integer, TDataLine>;
  24.     fDataByName: TDictionary<string, TDataLine>;
  25.  
  26.     fSortedById: TArray<TDataLine>;
  27.     fSortedByName: TArray<TDataLine>;
  28.  
  29.     fSynIDs: TSynDictionary;
  30.     fSynNames: TSynDictionary;
  31.  
  32.   public
  33.     constructor Create;
  34.  
  35.     procedure SortByID;
  36.     procedure SortByName;
  37.  
  38.     procedure Add(aTransID: integer; const aName: string);
  39.     function Count: integer;
  40.     function GetAllIDs: TArray<integer>;
  41.     function GetAllNames: TArray<string>;
  42.  
  43.     // Sequenced
  44.     function GetDataName(aID: integer): string;
  45.     function GetDataID(const aName: string): integer;
  46.     function Exists(aID: integer; const aName: string): boolean;
  47.  
  48.     // Dictionary
  49.     function GetNameFromDictionary(aID: integer): string;
  50.     function GetIDFromDictionary(const aName: string): integer;
  51.  
  52.     // TSynDictionary
  53.     function GetNameFromSyn(aID: integer): string;
  54.     function GetIDFromSyn(const aName: string): integer;
  55.  
  56.     // Sorted - TArray.BinarySearch
  57.     function GetNameFromSorted(aID: integer): string;
  58.     function GetIDFromSorted(const aName: string): integer;
  59.  
  60.   end;
  61.  
  62. var
  63.     gDataLookup: TDataLookup;
  64.  
  65. constructor TDataLookup.Create;
  66. begin
  67.   fData       := TObjectList<TDataLine>.Create;
  68.   fDataByID   := TDictionary<integer, TDataLine>.Create;
  69.   fDataByName := TDictionary<string, TDataLine>.Create;
  70.  
  71.   fSynIDs := TSynDictionary.Create(TypeInfo(TIntegerDynArray), TypeInfo(TDataLineArray));
  72.   fSynNames := TSynDictionary.Create(TypeInfo(TStringDynArray), TypeInfo(TDataLineArray));
  73. end;
  74.  
  75.  
  76. function TDataLookup.Count: integer;
  77. begin
  78.   Result := fData.Count;
  79. end;
  80.  
  81. procedure TDataLookup.SortByID;
  82. var
  83.   i: Integer;
  84. begin
  85.   SetLength(fSortedById, fData.Count);
  86.   for i := 0 to Pred(fData.Count) do
  87.   begin
  88.     fSortedById[i]               := TDataLine.Create;
  89.     fSortedById[i].TransactionID := fData.List[i].TransactionID;
  90.     fSortedById[i].CustomName    := fData.List[i].CustomName;
  91.   end;
  92.  
  93.   TArray.Sort<TDataLine>(fSortedById,
  94.   TDelegatedComparer<TDataLine>.Construct(
  95.     function(const Left, Right: TDataLine): Integer
  96.     begin
  97.       if Left.TransactionID > Right.TransactionID then Exit(1);
  98.       if Left.TransactionID < Right.TransactionID then Exit(-1);
  99.       Result:= 0;
  100.     end));
  101. end;
  102.  
  103. procedure TDataLookup.SortByName;
  104. var
  105.   i: Integer;
  106. begin
  107.   SetLength(fSortedByName, fData.Count);
  108.   for i := 0 to Pred(fData.Count) do
  109.   begin
  110.     fSortedByName[i]               := TDataLine.Create;
  111.     fSortedByName[i].TransactionID := fData.List[i].TransactionID;
  112.     fSortedByName[i].CustomName    := fData.List[i].CustomName;
  113.   end;
  114.  
  115.   TArray.Sort<TDataLine>(fSortedByName,
  116.   TDelegatedComparer<TDataLine>.Construct(
  117.     function(const Left, Right: TDataLine): Integer
  118.     begin
  119.       Result := CompareStr(Left.CustomName, Right.CustomName);
  120.     end));
  121. end;
  122.  
  123. procedure TDataLookup.Add(aTransID: integer; const aName: string);
  124. var vData: TDataLine;
  125. begin
  126.   vData := TDataLine.Create;
  127.   vData.TransactionID := aTransID;
  128.   vData.CustomName    := aName;
  129.   vData.SeqNo         := fData.Count + 1;
  130.  
  131.   fData.Add(vData);
  132.   fDataByID.Add(vData.TransactionID, vData);
  133.   fDataByName.Add(vData.CustomName, vData);
  134.  
  135.   fSynIDs.Add(vData.TransactionID, vData);
  136.   fSynNames.Add(vData.CustomName, vData);
  137.  
  138. end;
  139.  
  140. function TDataLookup.GetDataName(aID: integer): string;
  141. var
  142.   i: integer;
  143. begin
  144.   Result := '';
  145.   for i := 0 to Pred(fData.Count) do
  146.     if fData[i].TransactionID = aId then
  147.       Exit(fData[i].CustomName);
  148. end;
  149.  
  150. function TDataLookup.GetNameFromDictionary(aID: integer): string;
  151. var vDataLine: TDataLine;
  152. begin
  153.   if fDataByID.TryGetValue(aID, vDataLine) then
  154.     Result := vDataLine.CustomName;
  155. end;
  156.  
  157. function TDataLookup.GetIDFromDictionary(const aName: string): integer;
  158. var vDataLine: TDataLine;
  159. begin
  160.   Result := 0;
  161.   if fDataByName.TryGetValue(aName, vDataLine) then
  162.     Result := vDataLine.TransactionID;
  163. end;
  164.  
  165. function TDataLookup.GetNameFromSyn(aID: integer): string;
  166. var vDataLine: TDataLine;
  167. begin
  168.   vDataLine := TDataLine(fSynIDs.FindValue(aID)^);
  169.   Result := vDataLine.CustomName;
  170. end;
  171.  
  172. function TDataLookup.GetIDFromSyn(const aName: string): integer;
  173. var vDataLine: TDataLine;
  174. begin
  175.   vDataLine := TDataLine(fSynNames.FindValue(aName)^);
  176.    Result := vDataLine.TransactionID;
  177. end;
  178.  
  179.  
  180. function BinarySearchByID(const aData: TArray<TDataLine>; const aID: integer): integer;
  181. var L, H, i, c: Integer;
  182. begin
  183.   Result := 0;
  184.   L := 0; H := High(aData);
  185.   while L <= H do
  186.   begin
  187.     i := L + (H - L) shr 1;
  188.     c := CompareValue(aData[i].TransactionID, aID);
  189.     if c < 0 then
  190.       L := i + 1
  191.     else
  192.     begin
  193.       if c = 0 then
  194.         Exit(i);
  195.       H := i - 1;
  196.     end;
  197.   end;
  198. end;
  199.  
  200. function BinarySearchByName(const aData: TArray<TDataLine>; const aName: string): integer;
  201. var L, H, i, c: Integer;
  202. begin
  203.   Result := 0;
  204.   L := 0; H := High(aData);
  205.   while L <= H do
  206.   begin
  207.     i := L + (H - L) shr 1;
  208.     c := CompareStr(aData[i].CustomName, aName);
  209.     if c < 0 then
  210.       L := i + 1
  211.     else
  212.     begin
  213.       if c = 0 then
  214.         Exit(aData[i].TransactionID);
  215.       H := i - 1;
  216.     end;
  217.   end;
  218. end;
  219.  
  220. function TDataLookup.GetNameFromSorted(aID: integer): string;
  221. var vDataLine: TDataLine;
  222.     vIdx: integer;
  223. begin
  224.   vDataLine := TDataLine.Create;
  225.   vDataLine.TransactionID := aID;
  226.  
  227.   if TArray.BinarySearch<TDataLine>(fSortedById, vDataLine, vIdx,
  228.     TComparer<TDataLine>.Construct(
  229.       function (const Left, Right: TDataLine): Integer
  230.       begin
  231.        if Left.TransactionID < Right.TransactionID then
  232.           Result := -1
  233.         else if Left.TransactionID > Right.TransactionID then
  234.           Result := 1
  235.         else
  236.           Result := 0;
  237.  
  238.       end
  239.       ))
  240.   then
  241.     Result := fSortedById[vIdx].CustomName;
  242. end;
  243.  
  244. function TDataLookup.GetIDFromSorted(const aName: string): integer;
  245. var vDataLine: TDataLine;
  246.     vIdx: integer;
  247. begin
  248.   Result := 0;
  249.   vDataLine := TDataLine.Create;
  250.   vDataLine.CustomName := aName;
  251.  
  252.  if TArray.BinarySearch<TDataLine>(fSortedByName, vDataLine, vIdx,
  253.     TComparer<TDataLine>.Construct(
  254.       function (const Left, Right: TDataLine): Integer
  255.       begin
  256.         Result := CompareStr(Left.CustomName, Right.CustomName)
  257.       end
  258.       ))
  259.   then
  260.       Result := fSortedByName[vIdx].TransactionID;
  261. end;
  262.  
  263. function TDataLookup.GetDataID(const aName: string): integer;
  264. var
  265.   i: integer;
  266. begin
  267.   Result := 0;
  268.   for i := 0 to Pred(fData.Count) do
  269.     if fData[i].CustomName = aName then
  270.       Exit(fData[i].TransactionID);
  271. end;
  272.  
  273. function TDataLookup.Exists(aID: integer; const aName: string): boolean;
  274. var
  275.   i: Integer;
  276. begin
  277.   Result := false;
  278.   for i := 0 to Pred(fData.Count) do
  279.     if (fData[i].TransactionID = aId) or (fData[i].CustomName = aName) then
  280.       Exit(True);
  281. end;
  282.  
  283. function TDataLookup.GetAllIDs: TArray<integer>;
  284. var
  285.   i: Integer;
  286. begin
  287.   SetLength(Result, fData.Count);
  288.   for i := 0 to Pred(fData.Count) do
  289.     Result[i] := fData.List[i].TransactionID;
  290. end;
  291.  
  292. function TDataLookup.GetAllNames: TArray<string>;
  293. var
  294.   i: Integer;
  295. begin
  296.   SetLength(Result, fData.Count);
  297.   for i := 0 to Pred(fData.Count) do
  298.     Result[i] := fData.List[i].CustomName;
  299. end;
  300.  
  301. const
  302.   cChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  303. function GetRandomString(aNoOfChars: integer): string;
  304. var i: Integer;
  305. begin
  306.   SetLength(Result, aNoOfChars);
  307.   for i := 1 to aNoOfChars do
  308.     Result[i] := cChars[Random(Length(cChars)) + 1];
  309. end;
  310.  
  311. procedure GetRandomDataLine(out aTransID: integer; out aCustomName: string);
  312. begin
  313.   aTransId    := Random(maxint);
  314.   aCustomName := GetRandomString(RandomRange(12, 30));
  315. end;
  316.  
  317. procedure CreateRandomData(var aDataLookup: TDataLookup; aCount: integer);
  318. var
  319.   c: Integer;
  320.   vTransID: integer;
  321.   vCustomName: string;
  322. begin
  323.  aDataLookup := TDataLookup.Create;
  324.  c := 0;
  325.  while c < aCount do
  326.  begin
  327.    GetRandomDataLine(vTransID, vCustomName);
  328.    if Not aDataLookup.Exists(vTransID, vCustomName) then
  329.    begin
  330.      aDataLookup.Add(vTransID, vCustomName);
  331.      inc(c);
  332.    end;
  333.  end;
  334. end;
  335.  
  336. const
  337.   cMaxLoop: integer = 1000000;
  338.   cRunRecords: array of integer = [10, 50, 100, 1000, 10000];
  339.  
  340. var vArrayOfIDs: TArray<integer>;
  341.     vArrayOfNames: TArray<string>;
  342.  
  343. var a, i, vNoOfRecs, vTiming_u, vTiming_d, vTiming_s, vTiming_bs, vTiming_syn: integer;
  344.   vName: string;
  345.   vID: integer;
  346.   vSW: TStopWatch;
  347. begin
  348.   Randomize;
  349.  
  350.   Writeln('Get Name from ID (Search by integer):');
  351.   Writeln('records Sequenced  TArray.BinS  TDict  CustomBinS  TSynDict');
  352.   for vNoOfRecs in cRunRecords do
  353.   begin
  354.     CreateRandomData(gDataLookup, vNoOfRecs);
  355.     try
  356.       vArrayOfIDs := gDataLookup.GetAllIDs;
  357.  
  358.       // Sequenced
  359.       vSW := TStopWatch.StartNew;
  360.       for a := 1 to cMaxLoop div vNoOfRecs do
  361.         for i := Low(vArrayOfIDs) to High(vArrayOfIDs) do
  362.           vName := gDataLookup.GetDataName(vArrayOfIDs[i]);
  363.       vTiming_u := vSW.ElapsedMilliseconds;
  364.  
  365.       // Sorted - TArray.BinarySearch
  366.       gDataLookup.SortByID;
  367.       vSW := TStopWatch.StartNew;
  368.       for a := 1 to cMaxLoop div vNoOfRecs  do
  369.         for i := Low(vArrayOfIDs) to High(vArrayOfIDs) do
  370.           vName := gDataLookup.GetNameFromSorted(vArrayOfIDs[i]);
  371.       vTiming_s := vSW.ElapsedMilliseconds;
  372.  
  373.       // Dictionary
  374.       vSW := TStopWatch.StartNew;
  375.       for a := 1 to cMaxLoop div vNoOfRecs  do
  376.         for i := Low(vArrayOfIDs) to High(vArrayOfIDs) do
  377.           vName := gDataLookup.GetNameFromDictionary(vArrayOfIDs[i]);
  378.       vTiming_d := vSW.ElapsedMilliseconds;
  379.  
  380.       //BinarySearch
  381.       gDataLookup.SortByID;
  382.       vSW := TStopWatch.StartNew;
  383.       for a := 1 to cMaxLoop div vNoOfRecs  do
  384.         for i := Low(vArrayOfIDs) to High(vArrayOfIDs) do
  385.           vName := gDataLookup.fSortedById[BinarySearchByID(gDataLookup.fSortedById, vArrayOfIDs[i])].CustomName;
  386.       vTiming_bs := vSW.ElapsedMilliseconds;
  387.  
  388.        // Syn
  389.       vSW := TStopWatch.StartNew;
  390.       for a := 1 to cMaxLoop div vNoOfRecs  do
  391.         for i := Low(vArrayOfIDs) to High(vArrayOfIDs) do
  392.           vName := gDataLookup.GetNameFromSyn(vArrayOfIDs[i]);
  393.       vTiming_syn := vSW.ElapsedMilliseconds;
  394.  
  395.       Writeln(Format('%5s    %5s        %4s     %4s       %4s       %4s',[vNoOfRecs.ToString, vTiming_u.ToString, vTiming_s.ToString, vTiming_d.ToString, vTiming_bs.ToString, vTiming_syn.ToString]));
  396.  
  397.     finally
  398.       FreeAndNil(gDataLookup);
  399.     end;
  400.   end;
  401.  
  402.   Writeln;
  403.  
  404.   Writeln('Get ID from Name (Search by string):');
  405.   Writeln('records Sequenced  TArray.BinS  TDict  CustomBinS  TSynDict');
  406.   for vNoOfRecs in cRunRecords do
  407.   begin
  408.     CreateRandomData(gDataLookup, vNoOfRecs);
  409.     try
  410.       vArrayOfNames := gDataLookup.GetAllNames;
  411.  
  412.       // Sequenced
  413.       vSW := TStopWatch.StartNew;
  414.       for a := 1 to cMaxLoop div vNoOfRecs do
  415.         for i := Low(vArrayOfNames) to High(vArrayOfNames) do
  416.           vID := gDataLookup.GetDataID(vArrayOfNames[i]);
  417.       vTiming_u := vSW.ElapsedMilliseconds;
  418.  
  419.       // Sorted - TArray.BinarySearch
  420.       gDataLookup.SortByName;
  421.       vSW := TStopWatch.StartNew;
  422.       for a := 1 to cMaxLoop div vNoOfRecs  do
  423.         for i := Low(vArrayOfNames) to High(vArrayOfNames) do
  424.           vID := gDataLookup.GetIDFromSorted(vArrayOfNames[i]);
  425.       vTiming_s := vSW.ElapsedMilliseconds;
  426.  
  427.       // Dictionary
  428.       vSW := TStopWatch.StartNew;
  429.       for a := 1 to cMaxLoop div vNoOfRecs  do
  430.         for i := Low(vArrayOfNames) to High(vArrayOfNames) do
  431.           vID := gDataLookup.GetIDFromDictionary(vArrayOfNames[i]);
  432.       vTiming_d := vSW.ElapsedMilliseconds;
  433.  
  434.       //BinarySearch
  435.       gDataLookup.SortByName;
  436.       vSW := TStopWatch.StartNew;
  437.       for a := 1 to cMaxLoop div vNoOfRecs  do
  438.         for i := Low(vArrayOfNames) to High(vArrayOfNames) do
  439.           vID := BinarySearchByName(gDataLookup.fSortedByName, vArrayOfNames[i]);
  440.       vTiming_bs := vSW.ElapsedMilliseconds;
  441.  
  442.       //Syn
  443.       vSW := TStopWatch.StartNew;
  444.       for a := 1 to cMaxLoop div vNoOfRecs  do
  445.         for i := Low(vArrayOfNames) to High(vArrayOfNames) do
  446.           vID := gDataLookup.GetIDFromSyn(vArrayOfNames[i]);
  447.       vTiming_syn := vSW.ElapsedMilliseconds;
  448.  
  449.       Writeln(Format('%5s    %5s        %4s     %4s       %4s       %4s',[vNoOfRecs.ToString, vTiming_u.ToString, vTiming_s.ToString, vTiming_d.ToString, vTiming_bs.ToString, vTiming_syn.ToString]));
  450.  
  451.     finally
  452.       FreeAndNil(gDataLookup);
  453.     end;
  454.   end;
  455.  
  456.   Writeln;
  457.   Writeln('done...');
  458.  
  459.   readln;
  460.  
  461. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement