2010-09-14 86 views
6

我實現語言翻譯應用程序中通過將所有字符串運行時在TStringList中有:如何更快搜索Delphi TStringList中的名稱/值對?

procedure PopulateStringList; 
begin 
    EnglishStringList.Append('CAN_T_FIND_FILE=It is not possible to find the file'); 
    EnglishStringList.Append('DUMMY=Just a dummy record'); 
    // total of 2000 record appended in the same way 
    EnglishStringList.Sorted := True; // Updated comment: this is USELESS! 
end; 

然後我得到使用翻譯:

function GetTranslation(ResStr:String):String; 
var 
    iIndex : Integer; 
begin 
    iIndex := -1; 
    iIndex := EnglishStringList.IndexOfName(ResStr); 
    if iIndex >= 0 then 
    Result := EnglishStringList.ValueFromIndex[iIndex] else 
    Result := ResStr + ' (Translation N/A)'; 
end; 

反正這種方法需要大約30微秒找到一條記錄,是否有更好的方法來實現相同的結果?

UPDATE:以供將來參考我寫在這裏使用TDictionary所建議的新的實現(可與德爾福2009年和更新)

procedure PopulateStringList; 
begin 
    EnglishDictionary := TDictionary<String, String>.Create; 
    EnglishDictionary.Add('CAN_T_FIND_FILE','It is not possible to find the file'); 
    EnglishDictionary.Add('DUMMY','Just a dummy record'); 
    // total of 2000 record appended in the same way 
end; 


function GetTranslation(ResStr:String):String; 
var 
    ValueFound: Boolean; 
begin 
    ValueFound:= EnglishDictionary.TryGetValue(ResStr, Result); 
    if not ValueFound then Result := Result + '(Trans N/A)'; 
end; 

新GetTranslation函數執行快1000倍(在我的2000樣本記錄),然後是第一個版本。

+1

雖然IndexOf受益於正在排序的TStringList,但IndexOfName卻沒有。這並不是說它*在一些後代類中不能*,但TStringList不會覆蓋TStrings提供的基本線性搜索。 – 2010-09-15 01:16:47

+0

是的,我檢查過,它是相同的(所以我可以節省時間不排序列表。因爲我沒有修改它,它會更有意義的調用排序,而不是設置排序真(無論如何,我不會這樣做) 。謝謝。 – LaBracca 2010-09-15 09:57:48

回答

15

在Delphi 2009或更高版本中,我會在Generics.Collections中使用TDictionary < string> string>。 另請注意,有翻譯應用程序的免費工具,如http://dxgettext.po.dk/

+0

謝謝,是的,我知道tdxggettext,但我描述的翻譯的實現是已經完成了以前的開發人員,所以我只是試圖改善這一點,並用THasedStringList我取得了令人滿意的結果。無論如何,我會試一試(對於我個人的知識TDictionary建議你給了)。 – LaBracca 2010-09-14 20:56:21

+1

@VilleK:TDictionary和Delphi 2009中的其他一些泛型都存在一些bug,所以最好避免它,除非你使用的是Delphi 2010或XE。說實話,關於如何使用它及其功能的文檔很少。這給了我一個比它應該有的困難得多的時間。 – lkessler 2010-09-15 03:58:56

+0

是的,我記得在Delphi 2009中TDictionary存在一個bug,但現在我在Delphi 2010中使用它很多,並沒有遇到任何問題。我認爲它效果很好。另外TObjectDictionary在同一個單元中非常有用,因爲它可以選擇性地取得鍵和值的所有權。對我來說,Generics.Collections單位是從舊的Delphi版本升級的主要原因之一。 – 2010-09-15 09:15:29

17

THashedStringList應該會更好,我想。

+0

THANKS !!!!現在確定45條記錄從50毫秒傳遞到2毫秒,速度提高了25倍! – LaBracca 2010-09-14 14:34:53

+1

很酷 - 不知何故,我從來不知道這件事,我必須仔細研究它 – 2010-09-14 15:17:01

12

如果THashedStringList適合你,那太好了。它最大的弱點是每次更改列表的內容時,都會重建哈希表。所以只要你的名單很小或不經常改變,它就會適合你。

欲瞭解更多信息,請參閱:THashedStringList weakness,它提供了幾個選擇。

如果您有一個可能更新的大列表,您可能需要嘗試GpStringHashgabr,那麼在每次更改時都不必重新計算整個表格。

+0

我不需要更新列表,它只填充一次,所以我認爲我可以留在THashedStringList中,因爲現在瓶頸已經消失。 – LaBracca 2010-09-14 20:54:51

+0

對THashedStringList弱點的+1 – SOUser 2011-03-23 15:28:50

4

我認爲你沒有正確使用EnglishStringList(TStringList)。這是一個排序列表,您添加元素(字符串),然後對其進行排序,但是當您搜索時,您可以通過部分字符串(僅限名稱,IndexOfName)執行此操作。

如果您在排序列表中使用IndexOfName,則的TStringList不能使用Dicotomic搜索。它使用順序搜索。

(這是IndexOfName執行)

for Result := 0 to GetCount - 1 do 
    begin 
    S := Get(Result); 
    P := AnsiPos('=', S); 
    if (P <> 0) and (CompareStrings(Copy(S, 1, P - 1), Name) = 0) then Exit; 
    end; 

我認爲這是表現不佳的原因。
替代方法是使用2 TStringList:
*第一個(排序的)只包含「Name」和一個指向包含該值的第二個列表的指針;您可以使用Object屬性的「指針」將此指針實現爲第二個列表。
*第二個(未排序的)列表包含這些值。

當您搜索時,您在第一個列表中執行此操作;在這種情況下,您可以使用查找方法。當您找到名稱時,指針(用Object屬性實現)將爲您提供第二個列表中的值。

在這種情況下,Sorted List上的Find方法更有效,HashList(必須執行一個函數來獲取值的位置)。

問候。

鈀:對英語錯誤的打擾。

2

你也可以使用一個類幫手重新編程「IndexOfName」功能:

TYPE 
    TStringsHelper = CLASS HELPER FOR TStrings 
        FUNCTION IndexOfName(CONST Name : STRING) : INTEGER; 
        END; 

FUNCTION TStringsHelper.IndexOfName(CONST Name : STRING) : INTEGER; 
    VAR 
    SL : TStringList ABSOLUTE Self; 
    S,T : STRING; 
    I : INTEGER; 

    BEGIN 
    IF (Self IS TStringList) AND SL.Sorted THEN BEGIN 
     S:=Name+NameValueSeparator; 
     IF SL.Find(S,I) THEN 
     Result:=I 
     ELSE IF (I<0) OR (I>=Count) THEN 
     Result:=-1 
     ELSE BEGIN 
     T:=SL[I]; 
     IF CompareStrings(COPY(T,1,LENGTH(S)),S)=0 THEN Result:=I ELSE Result:=-1 
     END; 
     EXIT 
    END; 
    Result:=INHERITED IndexOfName(Name) 
    END; 

(或實現它在子字符串列表類,如果你不喜歡CLASS助手或沒有他們在您的德爾福版本)。

這將對已排序的TStringList使用二進制搜索,並對其他TStrings類進行順序搜索。