2012-11-06 3 views
29

필자는 Delphi-newbie 일종이며 레코드의 TList Sort 메서드를 호출하여 정수 값의 오름차순으로 레코드를 정렬하는 방법을 알지 못합니다.사용자 지정 비교자를 사용하여 제네릭 목록을 정렬하려면 어떻게합니까?

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

을 그리고 그러한 기록의 일반적인 목록 : 나는 다음과 같은 기록이

TListMyRecord = TList<TMyRecord>; 

이 도움말 파일의 코드 예제를 찾아 봤어을이 하나 발견

MyList.Sort(@CompareNames); 

클래스를 사용하기 때문에 사용할 수없는 클래스입니다. 그래서 나는 조금 다른 매개 변수를 사용하여 내 자신의 비교 함수를 작성하려고 :

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

그러나 컴파일러는 항상 던져 '충분하지 않은 매개 변수'- 나는 분명한 것 같다 open.Sort(CompareIntVal);로 호출 오류; ...

답변

36

Sort 과부하를 PMyRecord = ^TMyRecord; 난 항상 약간의 오류가 발생, 함수를 호출하는 다른 방법을 시도

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

PMyRecord과 : 그래서 도움말 파일에 가깝게 유지하려 당신이 사용되어야한다이 하나입니다

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

지금, 당신은 TComparer<TMyRecord>.Construct를 호출하여 IComparer<TMyRecord>를 만들 수 있습니다 . 이처럼 :

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

나는 익명의 방법으로 Comparison 기능을 서면으로 작성했습니다,하지만 당신은 평범한 구식 스타일이 아닌 OOP 기능 또는 개체의 방법을 사용할 수 있습니다.

비교 함수의 한 가지 잠재적 인 문제점은 정수 오버플로가 발생할 수 있다는 것입니다. 따라서 기본 정수 비교자를 대신 사용할 수 있습니다.

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

당신이 전역 변수 멀리 저장할 수 있도록 반복 TComparer<Integer>.Default를 호출하는 비용이 있습니다

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

고려해야 할 또 다른 옵션은 목록을 만들 때 비교 자에 전달하는 것입니다. 이 순서를 사용하여 목록을 정렬하는 경우보다 편리합니다.

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

그리고 당신은 내가 기록 또는 항목의 비표준 목록의 TList를을 알파벳순하는 훨씬 간단 수정 분류 기능을 발견

List.Sort; 
+0

감사의 verry 많이! ' Generics.Collections, ...', '사용'에 'TComparison'과'IComparer'에'undeclared'를 넣는 것 이외에 'uses'에 아무것도 넣지 않아도됩니까? 비교 : TComparison ; IntegerComparer : IComparer ; –

+0

또한 Generics.Defaults가 필요합니다. 아직 RTL 소스 코드를 찾았습니까? 그것은 당신을 도울 것입니다. –

+1

@David, 제공 한 코드에 대해 'TComparer'가 좋은 선택입니까? 'TComparer'는 추상 기본 클래스를위한 것입니다. 나는 당신의 코드에'TDelegatedComparer'를 사용할 것을 제안합니다. – TLama

2

로 목록을 정렬 할 수 있습니다.

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; 

및 목록을 정렬 호출 할 함수

Contacts.Sort(@CompareNames); 
+1

코드 샘플을 약간 정리해야 할 수 있습니다. 사용하지 않는 변수를 제거하십시오. 사용 예제를 추가하십시오. 구.을 정정하십시오. – Kromster

+4

원래 예제는 일반적인 목록을 정렬하는 것에 관한 것이지만이 예제에서는 표준 시나리오 인 TList (포인터 목록)를 사용하고 있습니다. 이는 다른 시나리오입니다. – ByteArts

0

나는 (내가 여기 모여 입력 기준) 내 솔루션을 공유하고자합니다.

표준 설정입니다. 제네릭 TObjectList에 단일 파일의 데이터를 보유하는 filedata 클래스입니다. 이 목록에는 fCurrentSortedColumn과 fCurrentSortAscending의 두 가지 개인 속성이있어 정렬 순서를 제어합니다. AsString 메서드는 경로와 파일 이름을 결합한 것입니다.

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

간결한 답 :

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

myList.Sort(
    TComparer<TMyRecord>.Construct(
    function(const Left, Right: TMyRecord): Integer 
    begin 
     Result := Left.intVal - Right.intVal; 
    end 
) 
); 
관련 문제