powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Сортировка массива записей по произвольному полю записи
25 сообщений из 43, страница 1 из 2
Сортировка массива записей по произвольному полю записи
    #40074256
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть запись

Код: pascal
1.
2.
3.
4.
5.
TMyRec = record
  field1,
  field2,
  field3: string;
end;



Есть массив

Код: pascal
1.
a: array of TMyRec;



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

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
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 подставлять любое поле, чтобы не размножать сортировку для каждого поля в коде? :)
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074257
Gerasimenko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox,

передавать индекс сортируемого поля как параметр
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074262
x1ca4064
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox

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


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

function Cmp(a,b:pointer):integer
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074265
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gerasimenko
antox,

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


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

Код: pascal
1.
a[i].field1>a[j].field1



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

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
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;



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

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
 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;
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074268
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
x1ca4064
antox

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


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

function Cmp(a,b:pointer):integer


А как это реализовать на примере?
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074269
Gerasimenko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox,

Код: pascal
1.
2.
3.
4.
5.
TMyRec = record
  field1,
  field2,
  field3: string;
end;



vs

Код: pascal
1.
2.
3.
TMyRec = record
  field: array [0..2] of string;
end;
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074271
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gerasimenko,

Так неудобно обращаться к полям :) Это можно запутаться, где чё хранится
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074276
x1ca4064
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox

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


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
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.



Можно и без указателей, если не нужна универсальность сортировки
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074284
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
x1ca4064,

Код: sql
1.
2.
3.
4.
5.
6.
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 , а мне что бы по любому имени, или имеется в виду, что для каждого поля будет такая функция:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
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;
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074288
Fr0sT-Brutal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
antox
Так тут все равно напрямую указано имя поля field1 , а мне что бы по любому имени, или имеется в виду, что для каждого поля будет такая функция:

Чтобы не указывать, делай массив. Обращаться можно через именованные константы, чтобы не запутываться (rec.Fields[fField1]). Теоретически можно и через RTTI, но ты вряд ли осилишь на текущем уровне, раз уж такие вопросы задаешь
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074299
x1ca4064
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox
x1ca4064,
Так тут все равно напрямую указано имя поля field1 , а мне что бы по любому имени, или имеется в виду, что для каждого поля будет такая функция:


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

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

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

procedure MySort(const ArrayData;const ElementCount,ElementSize:integer;CmpFun:TCmpFun)
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074307
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Fr0sT-Brutal
antox
Так тут все равно напрямую указано имя поля field1 , а мне что бы по любому имени, или имеется в виду, что для каждого поля будет такая функция:

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


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

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
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;
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074327
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox
Как (с помощью крутых и новейших технологий Delphi) вместо field1 подставлять любое поле
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
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;
));
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074329
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Или
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
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);
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074350
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А вот они - новые технологии ;) Спасибо
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074352
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
antox
Как (с помощью крутых и новейших технологий Delphi) вместо field1 подставлять любое поле
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
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 точку с запятой убрать
));



Работает отлично, точка с запятой лишняя
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074362
DimaBr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
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;
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074368
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
antox
Как (с помощью крутых и новейших технологий Delphi) вместо field1 подставлять любое поле
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
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;
));



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

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
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;
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074369
DimaBr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
antox

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

А теперь для вещественных полей напишите
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074373
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Суровые извращения. Непонятно только зачем.
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074376
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DimaBr
antox

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

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


:( сортирует, как текст
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074377
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rgreat
Суровые извращения. Непонятно только зачем.


Так, вроде, самый простой вариант сортировки массива записей по полям... Не знаю, как проще можно это сделать
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074384
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DimaBr
antox

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

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


Код: pascal
1.
2.
    //Result := AnsiCompareStr(par_a, par_b);
    Result := CompareValue(par_a, par_b);



Работает
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074385
DimaBr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Куда проще ? 22329310
...
Рейтинг: 0 / 0
Сортировка массива записей по произвольному полю записи
    #40074386
antox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DimaBr,

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

И так же тоже числа в сортируются как текст, как я понял
...
Рейтинг: 0 / 0
25 сообщений из 43, страница 1 из 2
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Сортировка массива записей по произвольному полю записи
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]