Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > Перечисляемые типы


Автор: ALeXandrK 17.8.2007, 16:19
Возможно ли оптимизировать данный код:

Код

...
TWeekDays = set of (wdMo, wdTu, wdWe, wdTh, wdFr, wdSa, wdSu);
...
var 
      StudingDays: TWeekDays;
begin
  if cbMo.Checked then
    StudingDays := StudingDays + [wdMo]
  else
    StudingDays := StudingDays - [wdMo];
  ...
end;


Таких проверок получается 7 (для каждого дня недели) и мне кажется, что можно это дело упростить,
но как?

Если есть интересные материалы/ссылки по работе со множествами, пишите.

Автор: sentry 17.8.2007, 16:32
А это разве перечислимый (я так называю) тип? Это вроде же множество. А перечислимый это
Код

TWeekDays = (wdMo, wdTu, wdWe, wdTh, wdFr, wdSa, wdSu);


А упростить можно вроде так:
Код

var
  X: TWeekDays;
begin
  X := [];
  if CheckBox1.Checked then
    X := X + [wdMo];
  if CheckBox1.Checked then
    X := X + [wdTu];
  // ...
end;

Автор: ALeXandrK 17.8.2007, 16:43
Да... ошибся - это и вправду множества. Жаль я тему не могу переименовать smile 

sentry: так я уже упростил, но все равно спасибо.

Я имел ввиду, что может можно написать что-то вроде:
Код

StudingDays := StudingDays + [wdMo]*Ord(cbMo.Checked);


Но так не выходит... а по мысли, Ord переводит значение Cheked (boolean) в 1 или 0, и
тогда при умножении мы добавляем значение в множество или нет соответственно.

Автор: Rennigth 17.8.2007, 17:02
В твоем случае без if не обойтить. Другие варианты будут еще белее громоздкие. Но есть симпотичные функции Include  и Exclude, которые повысят как утверждает борланд эффектифность кода:
Цитата

In Delphi code, Include adds the element I to the set S. The expression Include(S,I) corresponds to S := S + [I] but the Include procedure generates more efficient code.
S is a set type variable, and I is an expression of a type compatible with the base type of S. 

Код

TWeekDays = set of (wdMo, wdTu, wdWe, wdTh, wdFr, wdSa, wdSu);
...
var 
  StudingDays: TWeekDays;
begin
  if cbMo.Checked then
    Include(StudingDays, wdMo)  
  else
    Exclude(StudingDays, wdMo);
  ...
end;

Автор: ALeXandrK 17.8.2007, 17:04
Rennigth: про Include  и Exclude - хорошее замечание. Тоже читал про них в Help, но что-то даже и не задумался применять smile 
Руки то уже прикипели к + smile 

Автор: sentry 17.8.2007, 17:06
Цитата(ALeXandrK @  17.8.2007,  18:13 Найти цитируемый пост)
 Ord переводит значение Cheked (boolean) в 1 или 0, итогда при умножении мы добавляем значение в множество или нет соответственно.

Ord то переводит, только операции умножения мн-ва на число нет.

А если так:
Код

TEnum = (Nothing1, wdMo, Nothing2, wdTu, Nothing3, wdWe, Nothing4, wdTh, Nothing5, wdFr, Nothing6, wdSa, Nothing7, wdSu);
TWeekDays = set of TEnum;

//...

var
  X: TWeekDays;
begin
    X := X + [TEnum(Ord(CheckBox1.Checked))];
    X := X + [TEnum(Ord(CheckBox2.Checked)+2)];
end;


Извиняюсь, поправил, но все-таки if больше нравится smile 
Потом только проверять нужное в in, а на Nothing не обращать внимание.

Автор: ALeXandrK 17.8.2007, 17:11
sentry: красиво, но не работает smile 

Автор: sentry 17.8.2007, 17:20
Цитата(ALeXandrK @  17.8.2007,  18:41 Найти цитируемый пост)
 красиво, но не работает  

Я уже понял smile Эх, если бы Nothing Как-нибудь убрать или закономерность какую-нибудь найти. И цикл еще присобачить smile

Автор: ALeXandrK 17.8.2007, 17:25
Цитата(sentry @ 17.8.2007,  17:20)
Эх, если бы Nothing Как-нибудь убрать или закономерность какую-нибудь найти. И цикл еще присобачить smile

sentry: но это уже не оптимизация, а нагромажедение получется smile 

Автор: EvilsInterrupt 17.8.2007, 18:12
1)
В Пачеко книга по дельфи 5 том 1 на стр. 93, сказано, что юзать надо Include\Exclude реализуеются 1 маш. командой, когда +\- 13 + 6*n (6 кол-во битов во множестве). Вывод: надо проверить код генерируемый компиллером
2)
Код

  procedure TfrmMain.Button1Click(Sender: TObject);
  var
    tmp : TCheckBoxVariantSet;
  begin
    tmp := []; // выключаем все нафиг, чтобы недалать лишних else
    if CheckBox1.Checked then Include(tmp,var1);
    if CheckBox2.Checked then Include(tmp,var2);
    if CheckBox3.Checked then Include(tmp,var3);
    if CheckBox4.Checked then Include(tmp,var4);
    if CheckBox5.Checked then Include(tmp,var5);
    if CheckBox6.Checked then Include(tmp,var6);
    if CheckBox7.Checked then Include(tmp,var7);
    end;
  end;


и на такой код:
Код

    X := X + [TEnum(Ord(CheckBox1.Checked))];
    X := X + [TEnum(Ord(CheckBox2.Checked)+2)];

я бы не стал закладываться, т.к. выигрышь в скорости небольшой, а при измении кодогенерации разработчиком дельфи могут появится - трудно уловимые баги.

Автор: sentry 17.8.2007, 20:26
Цитата(EvilsInterrupt @  17.8.2007,  19:42 Найти цитируемый пост)
В Пачеко книга по дельфи 5 том 1 на стр. 93, сказано, что юзать надо Include\Exclude реализуеются 1 маш. командой, когда +\- 13 + 6*n (6 кол-во битов во множестве). Вывод: надо проверить код генерируемый компиллером

Посмотрел.

Тут записываем wdNo в eax с занулением старших битов. В Ebx ранее было загружено пустое множество.
Далее, логично делаем "или" ( al - 8 бит (256) ). Поскольку результат сейчас в eax, заносим его в ebx.
Код

Unit1.pas.34: X := X + [wdMo];
004540E8 0FB605FC404500   movzx eax,[$004540fc]
004540EF 0AC3             or al,bl
004540F1 8BD8             mov ebx,eax


И вот:
Код

Unit1.pas.34: Include(X, wdMo);
004540E8 80CB01           or bl,$01



Цитата(EvilsInterrupt @  17.8.2007,  19:42 Найти цитируемый пост)
выигрышь в скорости небольшой

С if побыстрее будет...

Автор: EvilsInterrupt 17.8.2007, 21:26
Я пока не вижу конкурентов моему варианту, но он получился благодаря книге Пачеко, так что это не мой! ;)
Можно ли еще вот в чем загадка для ума? ))) и знать ответ хочется, будем головоломствовать далее

Автор: ALeXandrK 17.8.2007, 22:03
Цитата(EvilsInterrupt @ 17.8.2007,  21:26)
... будем головоломствовать далее...

Раз к простой мат. операции свести не удается, то думаю, что вариант
Код

tmp := []; // выключаем все нафиг, чтобы недалать лишних else
    if CheckBox1.Checked then Include(tmp,var1);



Самый оптимальный. 

Тему считаю решенной, но новым вариантам будем рады smile 

Автор: MetalFan 19.8.2007, 10:00
можно мой вариант) может и работать будет помедленнее, но тут скорость вроде бы и не нужна
1. объявляем типы:
Код

TWeekDay = (wdMo, wdTu, wdWe, wdTh, wdFr, wdSa, wdSu);
TWeekDays = set of TWeekDay;

2. проставить в Tag TCheckBox'ам Ord значение TWeekDay при создании формы или в дизайне.
Код

procedure TForm1.OnCreate...
begin
  chkb1.Tag : = ord( wdMo );
...
  chkb7.Tag : = ord( wdSu );
end;

3. затем можно сделать либо так:
3.1 Всем чекам назначить один OnClick и...
Код

...
  if TCheckBox( Sender ).Checked then
    Include( FCheckedDays, TWeekDay(TCheckBox( Sender ).Tag)
  else
    Exclude( FCheckedDays, TWeekDay(TCheckBox( Sender ).Tag)

3.2 либо в цикле такимже образом "собрать" данные... разве что для удобства можно в OnCreate формы засунуть чеки в массив

Автор: EvilsInterrupt 19.8.2007, 10:53
MetalFan, Не есть гуд! Много не нужных действий, а ведь программер существо ленивое! Да и если говороить про дизайн тайм, то сво-во компонентов tag, в исходник u_main.pas или др. не положится, а это опять dfm или др. файлы таскать за собой, Зачем?! Неее я протев ;)))

Автор: ALeXandrK 19.8.2007, 11:18
Я вообще tag никогда не использую. Время пройдет и потом пойди разберись что ты в этот tag засунул.

Автор: MetalFan 19.8.2007, 11:58
Цитата(EvilsInterrupt @  19.8.2007,  10:53 Найти цитируемый пост)
Не есть гуд!

безосновательное заявление.

Цитата(EvilsInterrupt @  19.8.2007,  10:53 Найти цитируемый пост)
Много не нужных действий

если для тебя программирование - это набор ненужных действий, то это не для тебя.

Цитата(EvilsInterrupt @  19.8.2007,  10:53 Найти цитируемый пост)
программер существо ленивое!

по себе о всех не судят ;)

Цитата(EvilsInterrupt @  19.8.2007,  10:53 Найти цитируемый пост)
Да и если говороить про дизайн тайм, то сво-во компонентов tag, в исходник u_main.pas или др. не положится, а это опять dfm или др. файлы таскать за собой, Зачем?! 

всмысле таскать за собой? ты про что? или ты все компоненты на форме в рантайме создаешь???





Автор: sentry 19.8.2007, 12:21
Цитата(ALeXandrK @  19.8.2007,  12:48 Найти цитируемый пост)
Время пройдет и потом пойди разберись что ты в этот tag засунул.

Ну почему? Разобраться можно, если, конечно, в OnCreate глянуть...

Добавлено через 3 минуты и 14 секунд
Просто оставить комментарий - "что такое Tag смотри в OnCreate"  smile 
А можно прямо там и подробный комментарий написать, что, мол, в Tag'ах хранятся порядковые номера элементов
перечеслимого типа...

Автор: ALeXandrK 19.8.2007, 12:37
Цитата(sentry @ 19.8.2007,  12:21)
Просто оставить комментарий - "что такое Tag смотри в OnCreate"  smile 
А можно прямо там и подробный комментарий написать, что, мол, в Tag'ах хранятся порядковые номера элементов
перечеслимого типа...

Ну и опять таки получается больше телодвижений smile 
Так что на мой взгляд - это плохой вариант, неоптимальный.

Автор: EvilsInterrupt 19.8.2007, 12:57
Цитата
если для тебя программирование - это набор ненужных действий, то это не для тебя.

и:
Цитата
по себе о всех не судят ;)

Вот смотри ситуацию:
Я в моем проекте сначала реализовал работу приложения с XML-файлом, в качестве хранения настроек к приложению. Руководитель,
сказал немудрить ребята ручками все сделают. Но при этом объектов автоматизации где применяется моя прога, очень много!
Правка в ручную XML-файла занимает не менее 20 или 30 мин.
Че я сделал? Мне стало влом править файл и я добавил опрос COM-сервера, он выдал все что у него есть, я проставил напротив того чего мне надо галочки и нажал "Применить". Операция работы с XML-файлом стала занимать не больше 3 мин.

Скажи мне теперь, что лень это плохо и не выгодно? ;)

Цитата
всмысле таскать за собой?


Когда правится свойство компонента в дизайн-тайме, куда все ложится и хранится? Не в файл ли dfm ? Ну так вот, к примеру человек
писал для delphi 5, ну есть у него лицензионная копия потому и пишет, а его товарища к примеру другая дельфи и у которой формат dfm немного отличается. Что тогда? Тогда я его товарищу, не обходимо глянуть что и как там лежит, а для этого разобраться - а это иногда больше чем 10 мин. и поправить иногда 5 мин. и того 15 мин. в пустую убить. А ведь за 15 мин. можно под отладчиком и баги новые отладить!!! или чаю попить!

ЗЫ:
Мое мнение, а от него и такие ответы на форуме. Программист это не тот кто пишет код, а тот думает о последствиях кода! Т.е. сопровождении и ряда других последствиях.

Автор: MetalFan 19.8.2007, 16:29
Цитата(EvilsInterrupt @  19.8.2007,  12:57 Найти цитируемый пост)
Программист это не тот кто пишет код, а тот думает о последствиях кода!

ну-ну! Автомоблист - это не то, кто ездит на автомобиле, а тот, кто думает, что может попасть в аварию при езде на автомобиле...
а св-во tag у компонента AFAIK чуть ли не с первых версий делфи есть и деваться никуда не собирается.
и используется оно для хранения связанных с компонентом данных.

Автор: EvilsInterrupt 19.8.2007, 20:24
MetalFan, не будем офтопить ))) Я тута по делу,т.е. по теме smile))
Ради интересу обрисовал данный вопрос своему другу Sega-Zero\Завсегдатай_Delphikingom.ru он посоветовал юзать RTTI, т.к. говорит там никакой динамикой не пахнет и все эти возврат имени класса и т.д. являются статической дурью.

Вот цитата из лога переписки с ним:
Цитата

 Sega-Zero (воскресенье, 2007-Август-19   21:21:01)
требования:
- uses TypeInfo;
- все чекбоксы лежат на панели и больше на панели ничего не лежит
- каждый чекбокс называется в соответствии с днем недели, к примеру cbMon, cbTue...
Код

type
  TWeekDay=(wdMon, wdTue, wdWed, wdThu, wdFri, wdSat, wdSun);
  TWeekDays = set of TWeekDay;

function GetCheckedDays: TWeekDays;
var
  I: Integer;
begin
  Result := [];
  for I := 0 to CheckBoxesPanel.ControlCount - 1 do
  with TCheckBox(CheckBoxesPanel.Controls[I]) do
  if Checked then 
    Include(Result, GetEnumValue(TypeInfo(TWeekDay), 'wd' + Copy(Name, 2, Length(Name)));
end;

 Sega-Zero (воскресенье, 2007-Август-19   21:22:19)
код не быстрее, но красивее smile

Автор: MetalFan 19.8.2007, 21:04
EvilsInterrupt, да те же яйца... на имя закладываться или в tag значение для проверки засунуть... да и операции со строками более ресурсоемкие, хотя в контексте данной задачи это фиолетово...

Автор: aktuba 19.8.2007, 21:38
Цитата

EvilsInterrupt, да те же яйца... на имя закладываться или в tag значение для проверки засунуть... да и операции со строками более ресурсоемкие, хотя в контексте данной задачи это фиолетово...


 smile Полностью согласен. Зачем использовать тут строки? Зачем тут RTTI??? Это уже усложнение, а не упрощение.

Автор: EvilsInterrupt 19.8.2007, 23:10
aktuba, ты мой пост полностью прочеЛ? ))) там написано, что вариант не мой!!!
А второй:
Цитата

 Sega-Zero (воскресенье, 2007-Август-19   21:22:19)
код не быстрее, но красивее 


В чем конечно я частично соглашаюсь smile

ЗЫ:
Учимся внимательно читать посты!

ЗЫ2:
Специалист обязан знать тонкости специфики и чем больше тем лучше

Автор: aktuba 19.8.2007, 23:37
Цитата

aktuba, ты мой пост полностью прочеЛ? ))) там написано, что вариант не мой!!!


Да прочел я. Но в корне не согласен с тем, что написано:

Цитата

- uses TypeInfo;
- все чекбоксы лежат на панели и больше на панели ничего не лежит
- каждый чекбокс называется в соответствии с днем недели, к примеру cbMon, cbTue...


Такие ограничения в данной задаче - все равно, что за хлебом дорогу перейти = слетать на самолете. Для чего? Бред какой-то...

Цитата

Код

type
  TWeekDay=(wdMon, wdTue, wdWed, wdThu, wdFri, wdSat, wdSun);
  TWeekDays = set of TWeekDay;
function GetCheckedDays: TWeekDays;
var
  I: Integer;
begin
  Result := [];
  for I := 0 to CheckBoxesPanel.ControlCount - 1 do
  with TCheckBox(CheckBoxesPanel.Controls[I]) do
  if Checked then 
    Include(Result, GetEnumValue(TypeInfo(TWeekDay), 'wd' + Copy(Name, 2, Length(Name)));
end;



Если это называется красивый код - то я вообще не разбираюсь в красоте кода. Надо было по всей форме рекурсивно пробежаться  smile 

Цитата

Sega-Zero (воскресенье, 2007-Август-19   21:22:19)
код не быстрее, но красивее 


Для меня не только не быстрее, но и не красивее, не удобнее, не... Дальше продолжи сам.

Цитата

ЗЫ:
Учимся внимательно читать посты!

ЗЫ2:
Специалист обязан знать тонкости специфики и чем больше тем лучше 


А это тут при чем? Есть опыт работы с RTTI и что? Теперь на каждом шагу применять? Таким подходом - лучше тогда отбросить ООП, Delphi и т.д. и сесть за маш.коды - вот где красота и скорость будет. В Delphi всегда главным преимуществом было четкость, легкая читаемость кода. Не надо для перевозки ящика пива железнодорожный состав нанимать!!! Хватит и попутку поймать.


EvilsInterrupt, надеюсь теперь я понятно изложил мысли. И еще, в дополнении, специалист обязан не только знать специфики, но и грамотно применять их. Вот это лучше понять как можно раньше.

Автор: ALeXandrK 20.8.2007, 02:09
Ребята! Вы ушли глубоко в  smile 

И мне кажется уже начали переходить на личности. 
Тут каждый высказывает личное мнение. Не нужно никого переубеждать.

Я уже 13 постов назад выбрал для себя оптимальный вариант. 

Остановитесь или пишете друг другу личные сообщения - к чему тут то разводидить беседу.
Я б еще понял, если бы предлагались варианты оптимальнее, но вы ж уже такое нагородили.... smile 
Усложнили задачу по самые небалуй smile 


P.s.: Не ожидал такой активности в теме. Я понимаю, если б обсуждалось как организовать оптимальный генетический алгоритм
составления какого-нибудь расписания. Тут то задачка... так... чисто для красоты кода, т.к. скорость здесь не имеет никакого значения!

Автор: aktuba 20.8.2007, 02:23
Цитата

Я б еще понял, если бы предлагались варианты оптимальнее, но вы ж уже такое нагородили....


Вот и я про то же  smile 

Автор: Gwire 23.8.2007, 13:04

Советую использоват не семь TCheckBox а один TCheckListBox из закладки Additional.

Код
type
  TEnumWD = (wdMo=1, wdTu=2, wdWe=3, wdTh=4, wdFr=5, wdSa=6, wdSu=7);
  TWeekDays = set of TEnumWD;
var
  StudingDays: TWeekDays;
  
procedure TForm1.CheckListBox1Click(Sender: TObject);
var i: Byte;
    P: Byte;
begin
    StudingDays:= []; // Так как посоветовал EvilsInterrupt
    for i:= 1 to 7 do 
    begin
        P:= Ord(CheckListBox1.Checked[i-1])*i;  // Так как ты хотел
        Include( StudingDays, TEnumWD( P ) );
    end;
end;


Автор: ALeXandrK 23.8.2007, 13:11
Неплохая мысль. Про существование TCheckListBox я и забыл smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)