Containers in Delphi (2)

Source: Internet
Author: User

Tstrings class

For efficiency considerations, Delphi does not define strings as classes like C ++ and Java. Therefore, tlist itself cannot directly store strings, and string lists are widely used, therefore, Borland provides the tstrings class as the base class for storing strings. It should be said that it is another important Delphi container class except the tlist class.

Note that the tstrings class itself contains many abstract pure virtual methods, so it cannot be directly used after instantiation, the tstrings class must inherit a base class to implement all the abstract pure virtual methods for the actual string list. Management . Although the tstrings class itself is an abstract class, it should be said that it is a template class using the template mode. It provides many predefined algorithms to add or delete strings in the list, sort the strings in the list by subscript and save them to the stream. Associates each string with the same object and provides key-value pairs.

Because the tstrings class itself is an abstract class and cannot be instantiated, Delphi provides a tstrings subclass of the tstringlist to provide the default implementation of the tstrings class, which is usually used in actual use, we should use the tstringlist class to store the string list. The Code is as follows:

VaR templist: tstrings;
Begin
Templist: = tstringlist. Create;
Try
Templist. Add ('string 1 ');
...
Finally
Templist. Free;
End;
End;

The tstrings class is widely used. Many VCL class attributes are of the tstrings type, such as the lines attribute of the tmemo component and the items attribute of the tlistbox. The following describes common usage of the tstrings class.

Common usage of the tstrings class

A string in the subscript access list is the most common operation. The usage is as follows:

Stringlist1.strings [0]: = 'string 1 ';

Note that in Delphi, almost all the lower mark of the list is based on 0, that is, strings [0] is the first string in the list. In addition, because the strings attribute is the default attribute of the string list class, you can omit strings and directly use the following simple method to access the string:

Stringlist1 [0]: = 'string 1 ';

You can use the IndexOf method to locate a specific string in the list. The IndexOf method returns the index value of the first matched string in the string list, -1 is returned if no matching string exists. For example, you can use the IndexOf method to check whether a specific file exists in the file list box. The Code is as follows:

if FileListBox1.Items.IndexOf('TargetFileName') > -1 ...

It is inconvenient that the TStrings class does not provide a method to search for indexes of the same string except the first one. It can only be implemented by traversing the string list by itself, this is not as powerful and convenient as the template container class in C ++ and related template algorithms. The following is a diagram of traversing the string list. The Code traverses all strings in the list box and converts them all to uppercase strings:

procedure TForm1.Button1Click(Sender: TObject);var Index: Integer;
begin
 for Index := 0 to ListBox1.Items.Count - 1 do  
ListBox1.Items[Index] := UpperCase(ListBox1.Items[Index]);
end;

As we can see, to Add a string to the string list, you can use the Add method directly. However, the Add method can only Add the string to the end of the list, to add a string at the specified position in the list, you must use the Insert method. The following Code adds a string at the 2 position of the index in the list:

StringList1.Insert(2, 'Three');

To add all strings in a string list to another string list, use the AddStrings method as follows:

StringList1.AddStrings(StringList2); 

To clone all the contents of a string list, use the Assign Method. For example, the following method copies the string list in Combox1 to Memo1:

Memo1.Lines. Assign (ComboBox1.Items );

Note that after the Assign method is used, all the original strings in the target string list will be lost.

Same object Association

As mentioned above, we can bind strings with objects. We can use AddObject or InsertObject to add objects associated with strings to the list, you can also use the Objects attribute to directly associate an object with a string at a specific position. In addition, the TStrings class also provides the IndexOfObject method to return the index of the specified object. The same Delete, Clear, and Move methods can also act on the object. However, we cannot add an object that is not associated with the same string to the string.

Same view interaction

People who just learned how to use Delphi will be shocked by the powerful interface interaction design functions of Delphi IDE. For example, we put a ListBox on the form, double-click the Items attribute (TStrings type) of the object Inspector. In the displayed dialog box, enter some strings and click OK to close the dialog box, the string we just entered appears in the ListBox on the form.

 

But we cannot find the Code related to ListBox in the source code of TStrings and the default implementation class TStringList. How can we achieve this interface interaction?

The secret is that the Items attribute type of TListBox is actually the TListBoxStrings class of TStrings. Let's take a look at the definition of this class:

 TListBoxStrings = class(TStrings)
 *******
  ListBox: TCustomListBox;
 protected

 public
  function Add(const S: string): Integer; override;
  procedure Clear; override;
  procedure Delete(Index: Integer); override;
  procedure Exchange(Index1, Index2: Integer); override;
  function IndexOf(const S: string): Integer; override;
  procedure Insert(Index: Integer; const S: string); override;
  procedure Move(CurIndex, NewIndex: Integer); override;
 end;

We can see that the TListBoxStrings class implements all the Abstract methods of the TStrings class, and there is a private variable of ListBox in it. Let's take a look at the TListBoxStrings Add method:

function TListBoxStrings.Add(const S: string): Integer;
begin
 Result := -1;
 if ListBox.Style in [lbVirtual, lbVirtualOwnerDraw] then exit;
 Result := SendMessage(ListBox.Handle, LB_ADDSTRING, 0, Longint(PChar(S)));
 if Result < 0 then raise EOutOfResources.Create(SInsertLineError);
end;

You can see that TListBoxStrings does not save the added string internally, but directly sends the code for message implementation to the native list box control of Windows to add, while the native list box of Windows is an MVC component, when the internal data changes, the view display is automatically changed, which is why the strings we input in the designer are immediately displayed in the form list box.

As a result, Borland designs TStrings as an abstract class without providing a default storage method, because many interface components have different ways to store data internally, Borland decides to provide different storage and interaction methods for different components. If the component we want to compile has properties of the TStrings type and must interact with the interface or other resources, do not use TStringList, instead, a new class should be derived from TStrings to achieve better interaction design.

It should be noted that Delphi IDE only makes some special processing when using the Stream Mechanism of Delphi to save components to the DFM file of the Form Design file, the TStrings type attributes of Published can be automatically saved and loaded. Below is a text representation of a ListBox stored in DFM of the Form Design file (in the form design phase, we can directly use the View As Text right-click menu command to see the following Text). We can note that the two Items strings we entered were saved during design:

 object ListBox1: TListBox
  Left = 64
  Top = 40
  Width = 145
  Height = 73
  ItemHeight = 16
  Items.Strings = (
   'String1'
   'String2')
  TabOrder = 1
 end

Then, if you run the program, The VCL library uses the stream to import Items from the DFM resource compiled into the executable file. the Strings list is loaded to the interface to implement the design and runtime.

Key-Value Pair

In the actual development process, we often encounter operations similar to dictionary locating operations that use keys to find the corresponding value, such as searching the user's login password through the user name. In C ++ and Java, both the standard template library and JDK provide Map classes to implement the key-value mechanism, but the VCL library of Delphi does not provide such classes, however, the TStrings class provides a simple Map replacement implementation, that is, the Name-Value pair.

For TStrings, the so-called Name-Value pair is actually a string that contains the = sign like 'key = value'. the left part of the equal sign is Name, the right part of the equal sign is Value. The TStrings class provides attribute methods such as IndexOfName and Values to operate the Name-Value pair. The usage diagram is as follows:

VaR
Stringlist1: tstrings;
Begin
StringList1: = TStringList. Create;
// Add username-Password pair
StringList1.Add ('hubdog = aaa ');
StringList1.Add ('hubcat = bbb ');
....
// Search for the password based on the user name hubdog
Showmessage (StringList1.Values [StringList1.IndexOfName ('hubdog')]);
End;

Starting from Delphi7, The TStrings class adds a NameValueSeparator attribute. We can use this attribute to modify the default Name-Value delimiter to a symbol other than the = symbol. It should also be noted that the Name in the Name-Value pair of TStrings can not be unique, which is a bit similar to the MultiMap in C ++, in this case, the Value obtained through the Values [Names [IndexOfName] subscript operation is not necessarily what we need. In addition, the search and locating of the Name-Value pair of the TStrings class adopts the Traversal method, unlike Map in Java and C ++, it is implemented based on hash tables or trees. Therefore, the search and positioning efficiency is very low and is not suitable for scenarios with high performance requirements. However, starting from Delphi6, The VCL Library provides a hash table-Based String list class THashedStringList class in the IniFiles unit, which can greatly improve the search and location speed.

 

THashedStringList class

Generally, the simplest way to search for values through keys is to traverse the list and compare the keys in the list. If they are equal, the corresponding key value is obtained. However, this simple method is also the most efficient one. This method is acceptable when there are few projects in the list. However, if there are many projects in the list, this method will greatly affect the running speed of the software. In this case, we can use a hash table to quickly access the elements in the list through key values. Since this book is not a book on data structures and algorithms, I have no idea here to discuss the theoretical knowledge behind hash tables, we only need to know that the hash can quickly locate the corresponding value through the key. Non-computer professionals who are interested in this can view the relevant books. I will not go into details here.

The THashedStringList class provided in Delphi6 does not provide any new methods. It only optimizes the performance of the IndexOf and IndexOfName functions through the hash table, the following example demonstrates the performance difference between TStringList and THashedStringList:

Unit CHash;
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Inifiles;
Type
TForm1 = class (TForm)
Button1: TButton;
Procedure Button1Click (Sender: TObject );
Procedure FormCreate (Sender: TObject );
Procedure FormDestroy (Sender: TObject );
*******
{Private declarations}
HashedList: THashedStringList;
DesList: TStringList;
List: tstringlist;
Public
{Public declarations}
Procedure hash;
Procedure iterate;
End;
VaR
Form1: tform1;
Implementation
{$ R *. DFM}
Procedure tform1.button1click (Sender: tobject );
VaR
I: integer;
Begin
Screen. cursor: = crhourglass;
Try
// Initialize the system
For I: = 0 to 5000 do
Begin
Hashedlist. Add (inttostr (I ));
List. Add (inttostr (I ));
End;
Hash;
Deslist. Clear;
Iterate;
Finally
Screen. cursor: = crdefault;
End;
End;
Procedure tform1.hash;
VaR
I, J: integer;
Begin
// Location Based on the hash table
For I: = 3000 to 4000 do
Begin
Deslist. Add (inttostr (hashedlist. indexof (inttostr (I ))));
End;
End;
Procedure tform1.iterate;
VaR
I, J: integer;
Begin
// Locate Based on Traversal
For I: = 3000 to 4000 do
Begin
Deslist. Add (inttostr (list. indexof (inttostr (I ))));
End;
End;
Procedure tform1.formcreate (Sender: tobject );
Begin
Hashedlist: = thashedstringlist. Create;
Deslist: = tstringlist. Create;
List: = tstringlist. Create;
End;
Procedure tform1.formdestroy (Sender: tobject );
Begin
Hashedlist. Free;
Deslist. Free;
List. Free;
End;
End.

The hash process in the above Code adopts the new thashedstringlist class to implement the search, while the iterate process uses the indexofname of the original tstringlist class for the search. After comparing the performance of the two processes, it can be seen that it takes only 0.7% of the time for hash to perform the same search action, while the iterate method takes 99.3% of the time. You can see that when the number of string list items is several thousand, the query speed based on hash tables is more than 100 times that of the original method.

 

However, although thashedstringlist is much faster than the tstringlist class, you need to re-calculate the hash function when searching strings again after adding or deleting strings, therefore, if you frequently delete or add compound operations for the same search, the execution speed may be slower than that of tstringlist.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.