Delphi中Double数组的动态排序

Delphi中Double数组的动态排序,delphi,Delphi,我在Delphi中创建了一个动态矩阵: AMatrix : Array of Array of Double; 假设我这样初始化它 SetLength(Amatrix,1000,10); 然后用一些值填充这个矩阵。现在,我想按照存储在第二维度特定位置的特定值(从0到9)对第一维度上的1000个项目进行排序 有没有一种方法可以创建一个可以直接应用于Amatrix的t比较程序,而无需创建其他数据结构(TList或TArray)?使用@R.Hoeck idea我编写了一个简单的演示程序,创建一个二

我在Delphi中创建了一个动态矩阵:

AMatrix : Array of Array of Double;
假设我这样初始化它

SetLength(Amatrix,1000,10);
然后用一些值填充这个矩阵。现在,我想按照存储在第二维度特定位置的特定值(从0到9)对第一维度上的1000个项目进行排序


有没有一种方法可以创建一个可以直接应用于Amatrix的t比较程序,而无需创建其他数据结构(TList或TArray)?

使用@R.Hoeck idea我编写了一个简单的演示程序,创建一个二维double数组,用随机数据填充,并使用给定列作为键对其进行排序

排序是通过为列创建索引/值列表,然后对列表进行排序来完成的

排序后,未排序数组中的数据被复制到另一个数组中,该数组将被排序

unit MatrixDemoMain;

interface

uses
  Winapi.Windows, Winapi.Messages,
  System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  System.Generics.Defaults,
  System.Generics.Collections;

type
    TMyRecord = record
        Index : Integer;
        Value : Double;
    end;
    TDynArray2OfDouble = array of array of Double;

    TForm1 = class(TForm)
        Button1: TButton;
        Memo1: TMemo;
        procedure Button1Click(Sender: TObject);
    private
        procedure DisplayArray(const Title : String;
                               const Arr   : TDynArray2OfDouble);
    end;

var
    Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
    AMatrix      : TDynArray2OfDouble;
    SortedMatrix : TDynArray2OfDouble;
    I, J         : Integer;
    SortCol      : Integer;
    Rec          : TMyRecord;
    List         : TList<TMyRecord>;
begin
    // Give dimension to unsorted array
    SetLength(AMatrix, 10, 3);
    // Give dimension to the sorted array
    SetLength(SortedMatrix, High(AMatrix) + 1, High(AMatrix[0]) + 1);
    // Select column to use as sort key
    SortCol := 2;

    // Fill matrix with random data
    for I := 0 to High(AMatrix) do begin
        for J := 0 to High(AMatrix[0]) do
            AMatrix[I, J] := Random(1000);
    end;
    DisplayArray('Unsorted:', AMatrix);

    // Create a list to sort data
    List := TList<TMyRecord>.Create;
    try
        for I := 0 to High(AMatrix) do begin
            Rec.Index := I;
            Rec.Value := AMatrix[I, SortCol];
            List.Add(Rec);
        end;
        // Sort the list
        List.Sort(TComparer<TMyRecord>.Construct(
                    function(const Left, Right: TMyRecord): Integer
                    begin
                        if Left.Value = Right.Value then
                            Result := 0
                        else if Left.Value > Right.Value then
                            Result := 1
                        else
                            Result := -1;
                    end)
                  );

        // Copy data from unsorted matrix using sorted list
        for I := 0 to High(AMatrix) do
            SortedMatrix[I] := AMatrix[List[I].Index];

        DisplayArray('Sorted on column ' + SortCol.ToString, SortedMatrix);
    finally
        FreeAndNil(List);
    end;
end;

// This procedure will display an array into the memo
procedure TForm1.DisplayArray(
    const Title : String;
    const Arr   : TDynArray2OfDouble);
var
    I, J    : Integer;
    Buf     : String;
begin
    Memo1.Lines.Add(Title);
    for I := 0 to High(Arr) do begin
        Buf := I.ToString + ') ';
        for J := 0 to High(Arr[0]) do
            Buf := Buf + Arr[I, J].ToString + '  ';
        Memo1.Lines.Add(Buf);
    end;
end;

end.
是否有一种方法可以创建一个
t比较程序
,它可以直接应用于[一个类型为
array of array of Double
]的变量],而无需创建其他数据结构(TList或TArray)

让我们尝试一下,但为了简单起见,我们将使用整数:

程序失败尝试;
{$APPTYPE控制台}
{$R*.res}
使用
SysUtils,Math,泛型。默认值,泛型。集合;
变量
A:整数数组的数组;
开始
A:=
[
[5, 2, 1, 3, 6],
[1, 2, 6, 3, 2],
[1, 6, 7, 8, 3],
[5, 7, 4, 2, 1],
[0, 4, 9, 0, 5],
[4, 1, 8, 9, 6]
];
TArray.Sort(A,
t比较程序.构造(
函数(常量左、右:整数数组):整数
开始
如果左[2]<右[2],则
结果:=-1
否则,如果左[2]>右[2],则
结果:=+1
其他的
结果:=0;
结束
)
);
对于变量i:=0至高(A)do
开始
书面语;
对于var j:=0到高(A[i])do
写(A[i,j]);
结束;
Readln;
结束。
不幸的是,这将无法编译,因为
整数数组
不是有效的类型,您可以将其用作
t
。请注意,这与不能使用整数数组作为函数的返回类型类似。解决方案也是一样的:创建一个定义为
整数数组的类型

程序解决方案1;
{$APPTYPE控制台}
{$R*.res}
使用
SysUtils,Math,泛型。默认值,泛型。集合;
类型
TIntArray=整数数组;
变量
A:数组的数组;
开始
A:=
[
[5, 2, 1, 3, 6],
[1, 2, 6, 3, 2],
[1, 6, 7, 8, 3],
[5, 7, 4, 2, 1],
[0, 4, 9, 0, 5],
[4, 1, 8, 9, 6]
];
TArray.Sort(A,
t比较程序.构造(
函数(常量左、右:数组):整数
开始
如果左[2]<右[2],则
结果:=-1
否则,如果左[2]>右[2],则
结果:=+1
其他的
结果:=0;
结束
)
);
对于变量i:=0至高(A)do
开始
书面语;
对于var j:=0到高(A[i])do
写(A[i,j]);
结束;
Readln;
结束。
但是在Delphi的现代版本中,您不需要创建自己的类型(事实上,这是一个坏主意,因为不同的类型不兼容)。相反,只需使用
TArray
,它实际上被定义为
整数数组
——这是一个动态整数数组,就像您的
整数数组一样:

程序解决方案2;
{$APPTYPE控制台}
{$R*.res}
使用
SysUtils,Math,泛型。默认值,泛型。集合;
变量
A:柏油虫阵列;
开始
A:=
[
[5, 2, 1, 3, 6],
[1, 2, 6, 3, 2],
[1, 6, 7, 8, 3],
[5, 7, 4, 2, 1],
[0, 4, 9, 0, 5],
[4, 1, 8, 9, 6]
];
TArray.Sort(A,
t比较程序.构造(
函数(常量左,右:TArray):整数
开始
如果左[2]<右[2],则
结果:=-1
否则,如果左[2]>右[2],则
结果:=+1
其他的
结果:=0;
结束
)
);
对于变量i:=0至高(A)do
开始
书面语;
对于var j:=0到高(A[i])do
写(A[i,j]);
结束;
Readln;
结束。
如果确实无法更改
A
的定义,可以使用强制转换:

程序解决方案3;
{$APPTYPE控制台}
{$R*.res}
使用
SysUtils,Math,泛型。默认值,泛型。集合;
变量
A:整数数组的数组;
开始
A:=
[
[5, 2, 1, 3, 6],
[1, 2, 6, 3, 2],
[1, 6, 7, 8, 3],
[5, 7, 4, 2, 1],
[0, 4, 9, 0, 5],
[4, 1, 8, 9, 6]
];
TArray.Sort(TArray(A),
t比较程序.构造(
函数(常量左,右:TArray):整数
开始
如果左[2]<右[2],则
结果:=-1
否则,如果左[2]>右[2],则
结果:=+1
其他的
结果:=0;
结束
)
);
对于变量i:=0至高(A)do
开始
书面语;
对于var j:=0到高(A[i])do
写(A[i,j]);
结束;
Readln;
结束。

最后,我还应该指出显而易见的一点:无需使用
t比较程序
,就可以对数据进行排序。(事实上,在Delphi 2009中引入泛型之前,您是被迫这样做的。)

据我所知,重新排列此类数组需要大量内存复制,同时将条目从一个点移动到另一个点。如果不需要对实际数组进行排序,只需要对数组中的数据进行排序引用列表,我可以发布一个很好的示例是的,我知道如何创建数组,我以前写过快速排序、插入排序和各种排序。我曾与TComparer合作过一点,但未能找到创建TComparer的方法来对数组的动态数组进行排序。我可以完全理解这个问题及其背后的问题。应该重新打开它,以获得合适的答案。我正在寻找一种方法,可以直接对矩阵进行排序,而不需要使用外部索引或第二个矩阵,就像对简单的动态数组进行排序一样,换句话说,我想创建一个可以应用于
Unsorted:
0) 293  547  16  
1) 238  503  543  
2) 428  950  663  
3) 150  444  739  
4) 160  388  373  
5) 945  382  417  
6) 863  818  392  
7) 344  131  617  
8) 91  458  330  
9) 370  717  191  
Sorted on column 2
0) 293  547  16  
1) 370  717  191  
2) 91  458  330  
3) 160  388  373  
4) 863  818  392  
5) 945  382  417  
6) 238  503  543  
7) 344  131  617  
8) 428  950  663  
9) 150  444  739