Текущий архив: 2004.10.24;
Скачать: CL | DM;
ВнизЕще по поводу Tlist. Сортировка. Найти похожие ветки
← →
mRodion © (2004-10-08 14:37) [0]Господа, огромное Вам спасибо за то, что вы есть и читаете иногда даже полный бред нас новичков...
А вопрос у меня такой:
ИспользуяTlist
строю свой список:
http://delphimaster.net/view/1-1097067854/
Хочу реализовать сортировку. Для этого методу Sort списка типаTlist
я должен передать в качестве параметра функцию типаTListSortCompare = function (Item1, Item2: Pointer): Integer;
Почему-то в качестве параметра нельзя передать такую функцию описанную в самом классе, реализующим список (например, в качествеprivate
метода классаTMyClass
в примере по ссылке выше).
Приходится описывать эту функцию вне класса:TMyClass = class
private
FMyList:TList
public
procedure Add (Item:TMyListItem);
procedure Delete (Index:integer);
property Items[Index:integer]:TMyListItem read GetItem
end;
function CompareMyItems (Item1, Item2: Pointer): Integer;
Но тогда если пользователь захочет использовать две копии моего списка, то обе копии будут использовать одну и ту же функцию сравненияCompareMyItems
?
Если да, то это не удобно, поскольку в каждой копии класса может быть свой тип сортировки (например по разным полям), и результат сравнения элементов для разных списков может быть разным.
Что делать в этом случае? Можно ли как-нибуть передать в качестве параметра функциюCompareMyItems
описанную внутри класса?
Надеюсь, ясен вопрос, а то что-то слишком длинный получился...
← →
Reindeer Moss Eater © (2004-10-08 14:44) [1]А если я имею экземпляр ТЛист никуда ни в какой класс не входящий?
И я хочу его отсортировать.
Мне что повеситься, или писать за каким-то лешим какой-то ненужный мне класс в котором одним из полей будет мой ТЛист?
← →
Суслик © (2004-10-08 14:45) [2]Ты определись, что ты вообще делаешь. Как мне видится ты несколько непоследовательно подходишь. Это выражается в том, что ты говоришь, что
"то обе копии будут использовать одну и ту же функцию сравнения"
и в тоже время
"то это не удобно, поскольку в каждой копии класса может быть свой тип сортировки".
Определись - пользователь использует одну фукнцию, есно с определенной функциональнсотю, или несколько разных?
Если несколько разных, то пусть сам пользователь и передает функцию сравнения - пусть сравнивает как ему хочется. ЭТо забота пользователя твоего класса.
Если все же речь идет об одной функции, то о каком разном типе сортироваке может идти речь? Я так полагаю, что ты имеешь в виду не совсем произвольный тип сортировки, а один из предопределенных? Если да, то организуй несколько функций. И сам переключайся переключайся между ними.
← →
KSergey © (2004-10-08 14:50) [3]В нее передать не получится
Но можно в модуле определить соотв. переменную типаTMyCompProc = procedure (Item1, Item2: Pointer): Integer of object;
implementation
var
MyCompFunc:TMyCompProc;
Ну и в методе Sort сначала присваивать этой переменной нужный метод класса, а потом вызывать оригинальную Sort.
В CompareMyItems пишем:function CompareMyItems
begin
Result := MyCompFunc(Item1, Item2);
end;
Вроде ничего особо не напутал....
← →
Reindeer Moss Eater © (2004-10-08 15:06) [4]type
TListSortCompare = function (Item1, Item2: Pointer): Integer;
TMyClass = class
private
FMyList:TList
fCompFunc : TListSortCompare;
public
procedure Add (Item:TMyListItem);
procedure Delete (Index:integer);
property Items[Index:integer]:TMyListItem read GetItem
property SortFunc : TListSortCompare read fCompFunc write fCompFunc;
end;
← →
Skier © (2004-10-08 15:20) [5]хм...а если так TMethod(AObjectProc).Code ?
← →
Суслик © (2004-10-08 15:22) [6]
> хм...а если так TMethod(AObjectProc).Code ?
можно и так, только надо будет первым (кажется) параметром передавать указатель на объект. Можно nil передавать.
Только тогда от клиента, передавшего метод объекта в качестве функции сравнения для tlist, нужно заручится гарантией, что он не будет в этом методе пользоваться self"ом.
← →
Суслик © (2004-10-08 15:25) [7]
> [5] Skier © (08.10.04 15:20)
не, так не выйдет... :)) Поторопился я :)
вызывать метод будет будет tlist. Он же не будет ничего передавать в качестве self. Так, что лажа будет.
ЗЫ. Может я что-то не понял, что было предложено. Поясни тогда свою мысль.
← →
mRodion © (2004-10-08 16:05) [8]2Суслик © (08.10.04 14:45) [2]:
Моя идея в том, чтобы сделать свой класс списка, тип сортировки в котором задается отдельным свойством. Я хочу вообще оградить пользователя моего списка от задания каких-бы то ни было функций сортировки. Только свойством.type
TSortType = (stSortByFilename, stSortByDate, stSortByComment);
TMyList = class
private
FMyList:TList;
FSortType:TSortType;
// e.t.c
public
procedure Sort;
// e.t.c
end;
Это для того, чтобы пользователь, используя мой TMyList, мог сделать следующиее:var
List1:TMyList;
List2:TMyList:
begin
List1 := TMyList.Create;
List2 := TMyList.Create;
//заполнение списков
List1.SortType := stSortByFilename;
List1.Sort;
List2.SortType := stSortByComment;
List2.Sort;
end;
Если в реализации методаTMyList.Sort
я буду вызывать функциюCompareMyItems
(см. мой вопрос), которая вынесена за пределы описания класса, то у меня стоит вопрос, как узнать тип сортировки в моем в конкретном экземпляре класса.
Если бы эта функция могла определаться внутриTMyList
, то я смог бы получить простой доступ к полюFSortType
и провести соответствующее сравнение. Очень похоже на то, что совет Reindeer Moss Eater © (08.10.04 15:06) [4] - это то, что мне нужно. Только я не понимаю, как в таком случае нужно определять функциюfCompFunc
в разделеimplementation.
← →
Reindeer Moss Eater © (2004-10-08 16:07) [9]как в таком случае нужно определять функцию fCompFunc в разделе implementation.
Её не обязательно определять там.
Её может определить пользователь твоего класса там где захочет.
← →
Reindeer Moss Eater © (2004-10-08 16:08) [10]implementation
....
function SortFunction (...):integer;
begin
.....
end;
end.
← →
Суслик © (2004-10-08 16:11) [11]
> , как узнать тип сортировки в моем в конкретном экземпляре
> класса.
не нужно узнавать.
Насколько я понимаю из твоего примера у тебя сортировок определенное количество видов. Т.е. у тебя TMyList не просто список, я список для определенных целей. Иначе я пример твоего не понимаю.
Тогда все просто - у тебя есть перечислимый признак SortType, гдеprocedure TMylist.fSetSortType(value: ...)
begin
case Value of
ByName: fSortProc := SortProcByName;
ByComment: fSortProc := SortPRocByComment;
...
end;
end;
где SortProcByName и SortProcByName под implementation.
в дальнейшем при вызове метода Sort у TList ему передается fSortProc.
← →
mRodion © (2004-10-08 16:46) [12]Понял, о чем вы толкуете, только мне нужно немножко не это.
Может быть, я просто других элементарных вещей не понимаю?
Хочу, чтобы функция CompareListItems работала примерно по такому принципу: пользователь задает порядок сортировки у каждого экземпляра класса с помощью одного поля класса (сортировать сначала по одному полю, потом по другому и т.д.). Т.о. создается список из полей сортировки, называемый SortOrderList. Этот список и есть то, что раньше я называл простым словом FSortType.
Соответственно, функция CompareListItems должна знать заданный порядок сортировки. Ее реализацию я вижу примерно такой:function CompareListItems (Item1, Item2: Pointer): Integer;
var
pdbitem1, pdbitem2:PTMyItem;
i:integer;
begin
pdbitem1 := item1;
pdbitem2 := item2;
result := 0;
i:=0;
if SortOrderList.Count <= 0 then exit;
while ((i<SortOrderList.Count) and (result = 0)) do begin
case SortOrderList.Items[i] of
udFilename :begin
if pdbitem1^.FileName < pdbitem2^.FileName then result := -1
else if pdbitem1^.FileName > pdbitem2^.FileName then result := 1
else result := 0;
end;
udDeviceName:begin
if pdbitem1^.DeviceName < pdbitem2^.DeviceName then result := -1
else if pdbitem1^.DeviceName > pdbitem2^.DeviceName then result := 1
else result := 0;
end;
udDateTime : begin
if pdbitem1^.Time < pdbitem2^.Time then result := -1
else if pdbitem1^.Time > pdbitem2^.Time then result := 1
else result := 0;
end;
udComment:begin
if pdbitem1^.Comment < pdbitem2^.Comment then result := -1
else if pdbitem1^.Comment > pdbitem2^.Comment then result := 1
else result := 0;
end;
end;
inc (i);
end;
end;
Так вот у меня в такой конфигурации одна проблема: я не знаю, как мне добраться до поля SortOrderList моего класса TMyList.
Если быть точным, то описание моего класса-списка выглядит примерно таким:TMyClass = class
private
FMyList:TList
public
SortOrderList:TSortOrderList;
procedure Add (Item:TMyListItem);
procedure Delete (Index:integer);
property Items[Index:integer]:TMyListItem read GetItem
end;
function CompareMyItems (Item1, Item2: Pointer): Integer;
Попробую задать вопрос так:
как мне в такой ситуации в реализации функции CompareMyItems добраться до поля SortOrderList моего класса?
← →
Суслик © (2004-10-08 16:57) [13]
> как мне в такой ситуации в реализации функции CompareMyItems
> добраться до поля SortOrderList моего класса?
через глобальную переменную ПОД implementation.
например так
procedure tmylist.sort();
begin
WhoStartsSort := self;
fList.Sort();
end;
Переменную WhoStartsSort использовать в процедуре сравнения.
С учетом того, что у тебя приложение однопоточное усе будет ок.
← →
mRodion © (2004-10-08 16:58) [14]2Суслик © (08.10.04 16:11) [11]
Ваш пример хорош и красив, но иногда заранее не знаешь, какой порядок сортировки предпочитает пользователь.
Один раз он захочет сортировать сначала по комментариям, потом по датам записей. А потом захочет другую сортировку: по комментариями, а потом по размеру файла, например.
Если есть такие данные:
коммент дата размер
ком1 1 12
ком2 3 10
ком2 1 15
ком1 1 6
И пользователь хочет первый тип сортировки, он может с помощью метода QuickSort получить такой список:
коммент дата размер
ком1 1 12
ком1 1 6
ком2 1 15
ком2 3 10
При этом видим, что размер не в порядке возрастания. Тогда пользователь может захотеть отсортировать вторым способом. Тогда может получить следующий список:
коммент дата размер
ком1 1 6
ком1 1 12
ком2 3 10
ком2 1 15
И когда пользовательских полей не 3, а 30, то я не берусь заранне предсказать все типы сортировок, которые могут понадобиться пользователю. Отсюда и пришла идея разрешить пользователю программы в самом интерфейсе задавать именно порядок сортировки. Почти как в excel"е.
← →
Reindeer Moss Eater © (2004-10-08 17:00) [15]Тогда свойством твоего класса надо делать не ссылку на процедуру сортировки, а тип сортировки.
А саму реализацию разных типов рисовать в модуле класса.
← →
mRodion © (2004-10-08 17:07) [16]ну так я именно это и пытаюсь сделать.
только не знаю заранее все типы сортировок.
← →
Суслик © (2004-10-08 17:09) [17]
> только не знаю заранее все типы сортировок.
Если ты не знаешь все возможные типы сортировки заранее, то у тебя нет иного выбора кроме как предоставить возможность клиенту задавать процедуру сортировки.
Об этом я тебе сказал с самого начала.
Ты хочешь невозможного - типа я (автор класса) ничего не знаю, но хочу сделать пользователю так здорово, чтобы он ничего не задавал, т.е. по сути тоже ничего не знал, но получал, что хотел. Ерунда какая-то: кто-то должен знать, иначе кирдык.
← →
mRodion © (2004-10-08 17:11) [18]2Суслик © (08.10.04 16:57) [13]
О! А это идея!
А переменную WhoStartsSort сделать типа TMyList!
Правильно понял?
← →
Суслик © (2004-10-08 17:13) [19]
> Правильно понял?
точно.
← →
mRodion © (2004-10-08 17:23) [20]Спасибо. Похоже в однопоточном случае это поможет.
Правда теперь меня будет мучить вопрос, как сделать это и для многопоточного варианта. Потому что в скором времени эти мои списки будут использоваться в отдельных потоках...
← →
Суслик © (2004-10-08 17:26) [21]
> использоваться в отдельных потоках...
Когда у это случится у тебя будет столько проблем, что ты про TMyList напрочь забудешь. А когда вспомнишь, твой уровень, очевидно, будет выше (с большинством проблем уже справился), так, что проблем реализовать многопоточный TMyList у тебя не будет.
:)
← →
mRodion © (2004-10-08 17:33) [22]А если я обрамлю изменение WhoStartsSort с помощью критических секций, это поможет в многопоточных использованиях данной конструкции?
procedure tmylist.sort();
begin
SortCriticalSection.Enter;
WhoStartsSort := self;
fList.Sort();
SortCriticalSection.Leave;
end;
← →
mRodion © (2004-10-08 17:34) [23]Спасибо за поддержку, но с потоками я уже эксперементирую :)
← →
Суслик © (2004-10-08 17:36) [24]
> А если я обрамлю изменение WhoStartsSort с помощью критических
> секций, это поможет в многопоточных использованиях данной
> конструкции?
В общем-то да...
Но в ракурсе действительно профессиональной разработки многопоточных приложений, заточенных на производительность, может быть не все так просто и однозначно. Крит. секция, это первое, что приходит в голову. Но бывают намного более тонкие методы взаимодействия потоков.
← →
Суслик © (2004-10-08 17:38) [25]
> но с потоками я уже эксперементирую :)
с ними не надо экспериментровать.
их надо плотно изучать.
поверь моему опыту: когда я прочел разные книги я понял насколья я мало понимал в потоках раньше, хотя считал себя великим экспериментаротом.
Страницы: 1 вся ветка
Текущий архив: 2004.10.24;
Скачать: CL | DM;
Память: 0.54 MB
Время: 0.032 c