我有多个数组,它们都以整数字段开头,从1到5个字段,这些就像是需要排序的索引,从最小到最大:
Alternatively, options can be an object containing these properties:
family {Number} - The record family. If present, must be the integer 4 or 6. If not provided, both IP v4 and v6 addresses are accepted.
hints: {Number} - If present, it should be one or more of the supported getaddrinfo flags. If hints is not provided, then no flags are passed to getaddrinfo. Multiple flags can be passed through hints by logically ORing their values. See supported getaddrinfo flags below for more information on supported flags.
all: {Boolean} - When true, the callback returns all resolved addresses in an array, otherwise returns a single address. Defaults to false.
All properties are optional.
目前我使用这种方法进行排序:
TArrayA = record
Field1:integer;
Field2:integer;
Field3:integer;
Field4:integer;
Field5:integer;
... //other fields, strings, integers... up to 50 fields
end;
ArrayA:=array of TArrrayA;
这可以胜任。虽然我需要对所有5个字段进行排序时有点慢, 这就是我逐个字段的方式,所以我对数组进行了5次排序。 有更好,更快的方法吗?
以下是示例:
// sort by Field1
top:=Length(ArrayA);
for counter := 0 to top do
begin
min := counter;
for look := counter + 1 to top do
if ArrayA[look].Field1 < ArrayA[min].Field1 then
min := look;
vTmpRecord := ArrayA[min];
ArrayA[min] := ArrayA[counter];
ArrayA[counter] := vTmpRecord;
end;
// now sort by Field2
top:=Length(ArrayA);
for counter := 0 to top do
begin
min := counter;
for look := counter + 1 to top do
if (ArrayA[look].Field1 = ArrayA[min].Field1) And
(ArrayA[look].Field2 < ArrayA[min].Field2) then
min := look;
vTmpRecord := ArrayA[min];
ArrayA[min] := ArrayA[counter];
ArrayA[counter] := vTmpRecord;
end;
答案 0 :(得分:3)
您可以使用内置的快速排序方法,使用自定义比较器对数组进行排序:
uses
System.Math,
System.Generics.Defaults,
System.Generics.Collections;
TArray.Sort<TArrayA>(ArrayA, TComparer<TArrayA>.Construct( function(const Left, Right: TArrayA): Integer
begin
if Left.Field1 = Right.Field1 then
begin
if Left.Field2 = Right.Field2 then
begin
Result := CompareValue(Left.Field3, Right.Field3);
end
else Result := CompareValue(Left.Field2, Right.Field2);
end
else Result := CompareValue(Left.Field1, Right.Field1);
end
));
我仅为前三个字段添加了代码,但您将了解如何为更多字段构建自己的比较器。
答案 1 :(得分:2)
您要做的最重要的事情是将排序算法与数据分开。这样,您可以使用不同的数据一次又一次地编写或使用单一排序算法
这样做的经典方法是使用比较排序。它们是排序算法,需要比较两个项目的比较函数,并返回小于的负整数,大于的正整数和相等的零。
因此,让我们首先为您的数据演示这样的比较函数。存储多个字段会使编写通用比较器变得困难。最好将字段放在数组中。完成后,您可以使用如下迭代进行比较lexicographically:
function CompareIntegerArray(const lhs, rhs: array of Integer): Integer;
var
i: Integer;
begin
Assert(Length(lhs) = Length(rhs));
for i := low(lhs) to high(lhs) do
if lhs[i] < rhs[i] then
exit(-1)
else if lhs[i] > rhs[i] then
exit(1);
exit(0);
end;
使用字典顺序,我们首先比较主要字段。如果它们不同,我们会得到答案,否则我们会继续进入二级领域。等等。如上所述,这种算法非常适合于迭代。
通过仅对数组进行一次排序,克服了方法的重大缺陷。
一旦你有了这个比较函数,你需要将它包装在一个外部比较函数中,该函数从记录字段中提取数据并填充数组。也许沿着这些方向:
type
TMyArray = array [1..5] of Integer;
function GetMyArray(const Value: TArrayA): TMyArray;
begin
Result[1] := Value.Field1;
Result[2] := Value.Field2;
....
end;
function MyCompare(const lhs, rhs: TArrayA): Integer;
begin
Result := CompareIntegerArray(
GetMyArray(lhs),
GetMyArray(rhs)
);
end;
现在,正如所承诺的那样,您可以将此比较功能与Generics.Collections
中的TArray.Sort<T>
等通用排序一起使用。这是Quicksort的实现,是一种平均复杂度为O(n log n)的比较排序。这通常会比你的O(n 2 )bubble sort产生巨大的好处。
如果您可以用实际数组替换记录,那么生活会更简单。另一个可能有用的选项是向记录添加一个方法,该方法返回一个整数数组,可以在字典比较函数中使用。
回顾一下: