2012-11-06 25 views
29

Ben bir Delphi-newbie ve ben kayıtları tamsayı değeri artan sıralamak için bir TList of Records Sıralama yöntemi deniyorum alamadım.Özel bir karşılaştırıcı kullanarak genel bir listeyi nasıl sıralarım?

type 
    TMyRecord = record 
    str1: string; 
    str2: string; 
    intVal: integer; 
    end; 

Ve böyle kayıtların genel bir listesi: Ben aşağıdaki gibi bir kayıt var

TListMyRecord = TList<TMyRecord>; 

yardım dosyalarında kod-örnek bulmak denediniz ve bu bir bulundu:

MyList.Sort(@CompareNames); 

Sınıfları kullandığı için kullanamadığım. Bu yüzden biraz farklı parametrelerle kendi karşılaştırmak fonksiyonunu yazmaya çalıştı:

function CompareIntVal(i1, i2: TMyRecord): Integer; 
begin 
    Result := i1.intVal - i2.intVal; 
end; 

Fakat derleyici hep atar 'yeterli parametreleri' - ı bariz görünüyor open.Sort(CompareIntVal); ile diyoruz hata; ...

cevap

36

Sort aşırı PMyRecord = ^TMyRecord; Hep bazı hata alıyorum, bir işlevi çağırmak için farklı yöntemler denedi

olarak

function SortKB(Item1, Item2: Pointer): Integer; 
begin 
    Result:=PMyRecord(Item1)^.intVal - PMyRecord(Item2)^.intVal; 
end; 

PMyRecord ile: o yüzden yardım dosyası daha yakın durmaya çalıştım kullandığınız gereken bu biridir:

procedure Sort(const AComparer: IComparer<TMyRecord>); 

Şimdi, TComparer<TMyRecord>.Construct arayarak bir IComparer<TMyRecord> oluşturabilir . Şunun gibi:

var 
    Comparison: TComparison<TMyRecord>; 
.... 
Comparison := 
    function(const Left, Right: TMyRecord): Integer 
    begin 
    Result := Left.intVal-Right.intVal; 
    end; 
List.Sort(TComparer<TMyRecord>.Construct(Comparison)); 

Ben isimsiz yöntemi olarak Comparison fonksiyonu yazdım, ama aynı zamanda bir düz eski tarz dışı cepten fonksiyonunu veya bir nesnenin bir yöntemi kullanabilirsiniz.

Karşılaştırma işlevinizdeki olası bir sorun, tamsayı taşması yaşayabilirsiniz. Böylece, varsayılan tamsayı karşılaştırıcısını kullanabilirsiniz.

Comparison := 
    function(const Left, Right: TMyRecord): Integer 
    begin 
    Result := TComparer<Integer>.Default.Compare(Left.intVal, Right.intVal); 
    end; 

bir genel değişken uzakta saklayın böylece art arda TComparer<Integer>.Default aramak pahalı olabilir:

var 
    IntegerComparer: IComparer<Integer>; 
.... 
initialization 
    IntegerComparer := TComparer<Integer>.Default; 

başka seçenek de listeyi oluştururken karşılaştırıcısı içinde geçmektir. Bu siparişi kullanarak sadece listeyi sıralarsanız daha uygun olur.

List := TList<TMyRecord>.Create(TComparer<TMyRecord>.Construct(Comparison)); 

Ve sonra ben kayıtların veya öğelerin standart dışı listesinin bir tlist alfabetik için daha basit modifiye sıralama işlevini bulundu

List.Sort; 
+0

Teşekkür verry çok! 'Kullanımlar' alanına ' Generics.Collections, ... 'kullanımından başka bir şey eklemem gerekiyor mu,' TComparison 've' IComparer'in' için bir 'kayıt dışı' aldım çünkü var Karşılaştırma: TComparison ; IntegerComparer: IComparer ; '? –

+0

Ayrıca, Generics.Defaults'a da ihtiyacınız var. Henüz RTL kaynak kodunu buldunuz. Bu sana yardımcı olur. –

+1

@David, TComparer'ın sağladığınız bir kod için iyi bir seçim olduğundan emin misiniz? “TComparer” soyut temel sınıftır. Kodunuz için 'TDelegatedComparer 'kullanmayı öneririm. – TLama

2

ile sıralayabilirsiniz.

Örnek

PList = ^TContact; 
    TContact = record    //Record for database of user contact records 
     firstname1 : string[20]; 
     lastname1 : string[20]; 
     phonemobile : Integer;  //Fields in the database for contact info 
     phonehome : Integer; 
     street1 : string; 
     street2 : string; 

type 
    TListSortCompare = function (Item1, 
           Item2: TContact): Integer; 
var 
    Form1: TForm1; 
    Contact : PList;   //declare record database for contacts 
    arecord : TContact; 
    Contacts : TList; //List for the Array of Contacts 

function CompareNames(i1, i2: TContact): Integer; 
begin 
    Result := CompareText(i1.lastname1, i2.lastname1) ; 
end; 

ve listesine sıralamak için çağırmak için işlev

Contacts.Sort(@CompareNames); 
+1

Kod örneğinizi biraz temizlemek isteyebilirsiniz. Kullanılmayan değişkenleri kaldırın. Kullanım örneği ekle. Sözdizimini düzeltin. – Kromster

+4

Özgün soru, genel bir listeyi sıralamaktı. Bu örnekte standart bir TList (işaretçiler listesi) kullanılıyor, bu da farklı bir senaryo. – ByteArts

0

(Ben burada toplanmış girişe göre) benim çözüm paylaşmak istiyorum.

Bu standart bir kurulumdur. Genel bir TObjectList'te tek bir dosyanın verilerini tutan bir filedata sınıfı. Liste, sıralama düzenini denetlemek için fCurrentSortedColumn ve fCurrentSortAscending öğesinin iki özel özniteliğine sahiptir. AsString yöntemi, birleştirilmiş yol ve dosya adıdır.

function TFileList.SortByColumn(aColumn: TSortByColums): boolean; 
var 
    Comparison: TComparison<TFileData>; 
begin 
    result := false; 
    Comparison := nil; 

    case aColumn of 
    sbcUnsorted : ; 
    sbcPathAndName: begin 
         Comparison := function(const Left, Right: TFileData): integer 
            begin 
             Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString); 
            end; 
        end; 
    sbcSize  : begin 
         Comparison := function(const Left, Right: TFileData): integer 
            begin 
             Result := TComparer<int64>.Default.Compare(Left.Size,Right.Size); 
             if Result = 0 then 
             Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString); 
            end; 
        end; 
    sbcDate  : begin 
         Comparison := function(const Left, Right: TFileData): integer 
            begin 
             Result := TComparer<TDateTime>.Default.Compare(Left.Date,Right.Date); 
             if Result = 0 then 
             Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString); 
            end; 
        end; 
    sbcState  : begin 
         Comparison := function(const Left, Right: TFileData): integer 
            begin 
             Result := TComparer<TFileDataTestResults>.Default.Compare(Left.FileDataResult,Right.FileDataResult); 
             if Result = 0 then 
             Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString); 
            end; 
        end; 
    end; 

    if assigned(Comparison) then 
    begin 
    Sort(TComparer<TFileData>.Construct(Comparison)); 

    // Control the sort order 
    if fCurrentSortedColumn = aColumn then 
     fCurrentSortAscending := not fCurrentSortAscending 
    else begin 
     fCurrentSortedColumn := aColumn; 
     fCurrentSortAscending := true; 
    end; 

    if not fCurrentSortAscending then 
     Reverse; 

    result := true; 
    end; 
end; 
1

özlü cevap:

uses 
    .. System.Generics.Defaults // Contains TComparer 

myList.Sort(
    TComparer<TMyRecord>.Construct(
    function(const Left, Right: TMyRecord): Integer 
    begin 
     Result := Left.intVal - Right.intVal; 
    end 
) 
); 
İlgili konular