Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
Есть запись

TMyRec = record
  field1,
  field2,
  field3: string;
end;


Есть массив

a: array of TMyRec;


есть его сортировка

for i:=1 to n-1 do
for j:=i+1 to n do
  if a[i].field1>a[j].field1 then
    begin
       tmp:=a[i];
       a[i]:=a[j];
       a[j]:=tmp;
    end;


Как (с помощью крутых и новейших технологий Delphi) вместо field1 подставлять любое поле, чтобы не размножать сортировку для каждого поля в коде? :)
31 май 21, 08:59    [22329116]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
Gerasimenko
Member

Откуда:
Сообщений: 4664
antox,

передавать индекс сортируемого поля как параметр
31 май 21, 09:01    [22329117]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
x1ca4064
Member

Откуда:
Сообщений: 1273
antox

Как (с помощью крутых и новейших технологий Delphi) вместо field1 подставлять любое поле, чтобы не размножать сортировку для каждого поля в коде? :)


Передавать в сортировку функцию сравнения:

function Cmp(a,b:pointer):integer
31 май 21, 09:07    [22329122]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
Gerasimenko
antox,

передавать индекс сортируемого поля как параметр


а как обратиться по индексу?

a[i].field1>a[j].field1


или писать Case на все случаи?

case indx of
0: begin
  for i:=1 to n-1 do
  for j:=i+1 to n do
    if a[i].field1>a[j].field1 then
      begin
         tmp:=a[i];
         a[i]:=a[j];
         a[j]:=tmp;
      end;
1: begin
  for i:=1 to n-1 do
  for j:=i+1 to n do
    if a[i].field2>a[j].field2 then
      begin
         tmp:=a[i];
         a[i]:=a[j];
         a[j]:=tmp;
      end;
2: begin
  for i:=1 to n-1 do
  for j:=i+1 to n do
    if a[i].field3>a[j].field3 then
      begin
         tmp:=a[i];
         a[i]:=a[j];
         a[j]:=tmp;
      end;
end;


Можно как-то хотя бы через указатели (не знаю, как это сделать)?

 fld : point;
begin
case indx of
0: fld := ^field1;
1: fld := ^field2;
2: fld := ^field2;
end;
  for i:=1 to n-1 do
  for j:=i+1 to n do
    if a[i].fld^ >a[j].fld^ then
      begin
         tmp:=a[i];
         a[i]:=a[j];
         a[j]:=tmp;
      end;
end;
31 май 21, 09:16    [22329126]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
x1ca4064
antox

Как (с помощью крутых и новейших технологий Delphi) вместо field1 подставлять любое поле, чтобы не размножать сортировку для каждого поля в коде? :)


Передавать в сортировку функцию сравнения:

function Cmp(a,b:pointer):integer


А как это реализовать на примере?
31 май 21, 09:18    [22329130]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
Gerasimenko
Member

Откуда:
Сообщений: 4664
antox,

TMyRec = record
  field1,
  field2,
  field3: string;
end;


vs

TMyRec = record
  field: array [0..2] of string;
end;
31 май 21, 09:21    [22329131]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
Gerasimenko,

Так неудобно обращаться к полям :) Это можно запутаться, где чё хранится
31 май 21, 09:27    [22329133]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
x1ca4064
Member

Откуда:
Сообщений: 1273
antox

А как это реализовать на примере?


type
  TCmpFun=function (a,b:pointer):integer;

function Cmp1(a,b:pointer):integer;
begin
  if TMyRec(a^).field1>TMyRec(b^).fileld1 then Result=1
  else if TMyRec(a^).field1<TMyRec(b^).fileld1 then Result:=-1
  else Result:=0;
end;

procedure MySort(Data:array of TMyRec;CmpFun:TCmpFun);
begin
  ....
  case CmpFun(@Data[i],@Data[j]) of
  -1:
    ....
  1:
    ...
  end;
end;

begin
  MySort(Data,@Cmp1);
end.


Можно и без указателей, если не нужна универсальность сортировки

Сообщение было отредактировано: 31 май 21, 09:33
31 май 21, 09:39    [22329139]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
x1ca4064,

function Cmp1(a,b:pointer):integer;
begin
  if TMyRec(a^).field1>TMyRec(b^).fileld1 then Result=1
  else if TMyRec(a^).field1<TMyRec(b^).fileld1 then Result:=-1
  else Result:=0;
end;


Так тут все равно напрямую указано имя поля field1, а мне что бы по любому имени, или имеется в виду, что для каждого поля будет такая функция:

function sField1(a,b:pointer):integer;
begin
  if TMyRec(a^).field1>TMyRec(b^).fileld1 then Result=1
  else if TMyRec(a^).field1<TMyRec(b^).fileld1 then Result:=-1
  else Result:=0;
end;

function sField2(a,b:pointer):integer;
begin
  if TMyRec(a^).field2>TMyRec(b^).fileld2 then Result=1
  else if TMyRec(a^).field2<TMyRec(b^).fileld2 then Result:=-1
  else Result:=0;
end;

function sField3(a,b:pointer):integer;
begin
  if TMyRec(a^).field3>TMyRec(b^).fileld3 then Result=1
  else if TMyRec(a^).field3<TMyRec(b^).fileld3 then Result:=-1
  else Result:=0;
end;
31 май 21, 09:56    [22329150]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
Fr0sT-Brutal
Member

Откуда:
Сообщений: 755
antox
Так тут все равно напрямую указано имя поля field1, а мне что бы по любому имени, или имеется в виду, что для каждого поля будет такая функция:

Чтобы не указывать, делай массив. Обращаться можно через именованные константы, чтобы не запутываться (rec.Fields[fField1]). Теоретически можно и через RTTI, но ты вряд ли осилишь на текущем уровне, раз уж такие вопросы задаешь
31 май 21, 10:26    [22329158]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
x1ca4064
Member

Откуда:
Сообщений: 1273
antox
x1ca4064,
Так тут все равно напрямую указано имя поля field1, а мне что бы по любому имени, или имеется в виду, что для каждого поля будет такая функция:


Да, для каждого поля своя функция сравнения, ее прототип можно сделать таким:

TCmpFun=function (const a,b:TMyRec):integer;

но тогда будет тяжко написать общую процедуру сортировки, которая позволит сортировать почти все:

procedure MySort(const ArrayData;const ElementCount,ElementSize:integer;CmpFun:TCmpFun)
31 май 21, 10:53    [22329178]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
Fr0sT-Brutal
antox
Так тут все равно напрямую указано имя поля field1, а мне что бы по любому имени, или имеется в виду, что для каждого поля будет такая функция:

Чтобы не указывать, делай массив. Обращаться можно через именованные константы, чтобы не запутываться (rec.Fields[fField1]). Теоретически можно и через RTTI, но ты вряд ли осилишь на текущем уровне, раз уж такие вопросы задаешь


Не благодари ;)

procedure Sort(field_name: string);
var
  i,j,n,f,findx: integer;
  val_i, val_j,  tmp: TMyRec;
  rtype: TRTTIType;
  fields: TArray<TRttiField>;
begin
  n:= High(A);

  rtype := TRTTIContext.Create.GetType(TypeInfo(TMyRec));
  fields := rtype.GetFields;

  findx:=-1;

  for f := Low(fields) to High(fields) do
    if fields[f].Name = field_name then findx := f;

  if findx < 0 then Exit;


  for i:=1 to n-1 do
  for j:=i+1 to n do
    begin
      val_i := a[i];
      val_j := a[j];

      if fields[findx].GetValue(@val_i).ToString > fields[findx].GetValue(@val_j).ToString then
        begin
          tmp:=a[i];
          a[i]:=a[j];
          a[j]:=tmp;
        end;
    end;
end;
31 май 21, 11:18    [22329193]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 12901
antox
Как (с помощью крутых и новейших технологий Delphi) вместо field1 подставлять любое поле
TArray.Sort<TMyRec>(a, TComparer<TMyRec>.Construct(
  function (const AItem1, AItem2: TMyRec): Integer
  begin
    Result := AnsiCompareStr(AItem1.Field1, AItem2.Field1);
  end;
));

TArray.Sort<TMyRec>(a, TComparer<TMyRec>.Construct(
  function (const AItem1, AItem2: TMyRec): Integer
  begin
    Result := AnsiCompareStr(AItem1.Field2, AItem2.Field2);
  end;
));


Сообщение было отредактировано: 31 май 21, 12:06
31 май 21, 12:14    [22329235]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 12901
Или
TMyRec = record
  field1,
  field2,
  field3: string;
  class function SortByField1(const AItem1, AItem2: TMyRec): Integer;
  class function SortByField2(const AItem1, AItem2: TMyRec): Integer;
end;

class function TMyRec.SortByField1(const AItem1, AItem2: TMyRec): Integer;
begin
   Result := AnsiCompareStr(AItem1.Field1, AItem2.Field1);
end;

class function TMyRec.SortByField2(const AItem1, AItem2: TMyRec): Integer;
begin
   Result := AnsiCompareStr(AItem1.Field2, AItem2.Field2);
end;

TArray.Sort<TMyRec>(a, TComparer<TMyRec>.Construct(TMyRec.SortByField1);
31 май 21, 12:19    [22329239]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
А вот они - новые технологии ;) Спасибо
31 май 21, 13:00    [22329278]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
_Vasilisk_
antox
Как (с помощью крутых и новейших технологий Delphi) вместо field1 подставлять любое поле
TArray.Sort<TMyRec>(a, TComparer<TMyRec>.Construct(
  function (const AItem1, AItem2: TMyRec): Integer
  begin
    Result := AnsiCompareStr(AItem1.Field1, AItem2.Field1);
  end;
));

TArray.Sort<TMyRec>(a, TComparer<TMyRec>.Construct(
  function (const AItem1, AItem2: TMyRec): Integer
  begin
    Result := AnsiCompareStr(AItem1.Field2, AItem2.Field2);
  end; //<- после end точку с запятой убрать
));


Работает отлично, точка с запятой лишняя
31 май 21, 13:06    [22329280]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
DimaBr
Member

Откуда:
Сообщений: 12091
for i:=1 to n-1 do
  for j:=i+1 to n do
    if (Index=0 and a[i].field1 > a[j].field1) or
       (Index=2 and a[i].field2 > a[j].field2) or
       (Index=3 and a[i].field3 > a[j].field3) then 
    begin
       tmp:=a[i];
       a[i]:=a[j];
       a[j]:=tmp;
    end;
31 май 21, 13:47    [22329310]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
_Vasilisk_
antox
Как (с помощью крутых и новейших технологий Delphi) вместо field1 подставлять любое поле
TArray.Sort<TMyRec>(a, TComparer<TMyRec>.Construct(
  function (const AItem1, AItem2: TMyRec): Integer
  begin
    Result := AnsiCompareStr(AItem1.Field1, AItem2.Field1);
  end;
));

TArray.Sort<TMyRec>(a, TComparer<TMyRec>.Construct(
  function (const AItem1, AItem2: TMyRec): Integer
  begin
    Result := AnsiCompareStr(AItem1.Field2, AItem2.Field2);
  end;
));


Модернизация под любое поле:

procedure SuperSortArray(field_name: string);
var
  rtype: TRTTIType;
  fields: TArray<TRttiField>;
  f,findx: Integer;
  par_a, par_b: string;
begin
  rtype := TRTTIContext.Create.GetType(TypeInfo(TMyRec));
  fields := rtype.GetFields;

  findx:=-1;

  for f := Low(fields) to High(fields) do
    if fields[f].Name = field_name then findx := f;

  if findx < 0 then Exit;

  TArray.Sort<TFieldTovar>(a, TComparer<TMyRec>.Construct(
  function (const AItem1, AItem2: TMyRec): Integer
  begin
    par_a := fields[findx].GetValue(@AItem1).AsString;
    par_b := fields[findx].GetValue(@AItem2).AsString;
    Result := AnsiCompareStr(par_a, par_b);
  end
  ));
end;
31 май 21, 13:58    [22329321]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
DimaBr
Member

Откуда:
Сообщений: 12091
antox

Модернизация под любое поле:

А теперь для вещественных полей напишите
31 май 21, 14:04    [22329324]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
rgreat
Member

Откуда:
Сообщений: 6711
Суровые извращения. Непонятно только зачем.
31 май 21, 14:08    [22329330]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
DimaBr
antox

Модернизация под любое поле:

А теперь для вещественных полей напишите


:( сортирует, как текст
31 май 21, 14:12    [22329333]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
rgreat
Суровые извращения. Непонятно только зачем.


Так, вроде, самый простой вариант сортировки массива записей по полям... Не знаю, как проще можно это сделать
31 май 21, 14:14    [22329334]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
DimaBr
antox

Модернизация под любое поле:

А теперь для вещественных полей напишите


    //Result := AnsiCompareStr(par_a, par_b);
    Result := CompareValue(par_a, par_b);


Работает
31 май 21, 14:20    [22329341]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
DimaBr
Member

Откуда:
Сообщений: 12091
Куда проще ? 22329310
31 май 21, 14:20    [22329342]     Ответить | Цитировать Сообщить модератору
 Re: Сортировка массива записей по произвольному полю записи  [new]
antox
Member

Откуда: РФ
Сообщений: 1267
DimaBr,

Так для этого придется для сортировки каждого массива (а у них разные поля) писать все поля в процедуру :) Руки отвалятся

И так же тоже числа в сортируются как текст, как я понял

Сообщение было отредактировано: 31 май 21, 14:16
31 май 21, 14:24    [22329343]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Delphi Ответить