问题
if i have a generics list with more field for example:
PMyList = record
Field1, Field2, ... FieldN : Integer;
end;
TMyList = List<PMyList>;
For order the list with criteria choose to runtime (for example: field2 then field2, or: field3 then field1 then field2 etc) there is some solution or i need to do a compare construct for all combination possibile of order that i want?
Mine idea was, if record is N field, i have thinked to a array so defined:
MyArray = array [1..n] of Integer;
and assign a progressive value to elements of array that determine criteria of sord for example if MyArray is as:
MyArray = (5, 1, 3, 4, 2)
mean that my list need to be sort first for field5, then for field1, then for field3, then for field4, then for field2. Mine question then is: can i to do it using one only construct compare for my list?
Thanks very much for help.
回答1:
I'm going to base the notation on your previous question. I'm also going to rename MyArray as FieldPriority.
So, FieldPriority[1] identifies the primary comparison field, FieldPriority[2] identifies the secondary comparison field and so on.
With this in place your compare function looks like this:
type
TMyRecord = record
Value: array [1..5] of Integer;
end;
function Compare(const Left, Right: TMyRecord): Integer;
var
i, Field: Integer;
begin
for i := 1 to 5 do
begin
Field := FieldPriority[i];
Result := CompareInt(Left.Value[Field], Right.Value[Field]);
if Result<>0 then
exit;
end;
end;
It all works much better if the integers in your record are declared as an array rather than individually. That allows you to index them as I do here.
Naturally this could all be generalised to handle arbitrary sized arrays.
回答2:
If I understand you right:
Comparer := TComparer<PMyList>.Construct(
function(const Left, Right: PMyList): Integer
var LV, RV, x: Integer;
begin
for x := Low(MyArray) to High(MyArray) do begin
case MyArray[x] of
1: begin
LV := Left.Field1;
RV := Right.Field1;
end;
2: begin
LV := Left.Field2;
RV := Right.Field2;
end;
...
else raise Exception.Create('Unhandled fileld index: '+IntToStr(MyArray[x]));
end;
Result := LV - RV;
if(Result <> 0)then Break;
end;
end);
回答3:
A method to take field priorities into account:
OverallCompareResult := Sum(CompareResult[i] * (1 shl Priority[i]))
(1 shl Priority[i] = 2 ^ Priority[i])
Priority[] for your example: (4, 1, 3, 2, 5)
CompareResult must be in (-1, 0, 1)
来源:https://stackoverflow.com/questions/8376182/order-list-with-criteria-choose-to-runtime