![]() |
|
|
#1
|
|||
|
|||
|
Вариантов выбора очень много , более 100 , есть две переменные по которым надо будет выбрать
Если взять оператор if then , if (a=0) and (b=1) then то смущает что вариантов более ста. Но если взять оператор Case of , то там проверка двух переменных нельзя, но он бы и работал быстрее. Подскажите есть еще варианты для двух переменных? Или только if then ? |
|
#2
|
||||
|
||||
|
использовать простую ХЭШ функцию и оператор CASE
Код:
function MySimpleHash(a, b: Byte): Word; begin Result := (a shl 8) or b; end; ... case MySimpleHash(a, b) of ... ... ... ... end; ... |
|
#3
|
|||
|
|||
|
Цитата:
Это сначало надо высчетать самому что переменные выдают? Код:
begin
ShowMessage(IntToStr(MySimpleHash(26, 49)));
case MySimpleHash(26, 49) of
6705:ShowMessage('26-49');
end;
end; |
|
#4
|
|||
|
|||
|
можно высчитать, можно просто функцию попроще использовать:
Код:
function MyCalcHash(a, b : byte) : Integer; begin Result := a*1000 + b; end; Код:
MyCalcHash(1,1) = 1001 MyCalcHash(10,8) = 10008 и т.д. А вообще, я бы подумал над динамическим выполением этого условия. Все, конечно, зависит от того, что конкретно надо делать в зависимости от значений a & b. Если просто присвоить значение какой-нить переменной или вызвать СТАНДАРТНУЮ функцию, то городить огород смыла нет. А вот если надо выполнить свой код, причем довольно объемный, да еще и в программе этот case при стандартном сценарии использования исполняется многократно, то тогда можно заморочиться с более динамической штукой. Как сделать: 1. Пишем базовый класс: Код:
interface
type
TDynamicActionBase = class
protected
procedure DoExecute; virtual; abstract;
function CanExecute(a, b : byte) : Boolean; virtual; abstract;
public
function Execute(a, b : byte): Boolean;
procedure Register(AList : TObjectList);
end;
implementation
procedure TDynamicActionBase.Register(AList : TObjectList);
begin
AList.Add(Self);
end;
function TDynamicActionBase.Execute(a, b : Byte) : Boolean;
begin
Result := CanExecute(a,b);
If Result Then DoExecute;
end;2. Теперь для каждого реального действия "рожаем" наследника и перекрываем у него соотв. методы: Код:
interface
type
TDynamicAction_1_1 = class(TDynamicActionBase)
protected
procedure DoExecute; override;
function CanExecute(a, b : byte) : Boolean; override;
end;
TDynamicAction_2_2 = class(TDynamicActionBase)
protected
procedure DoExecute; override;
function CanExecute(a, b : byte) : Boolean; override;
end;
implementation
procedure TDynamicAction_1_1.DoExecute;
begin
ShowMessage('1-1'); // Просто для демонстрации
end;
function TDynamicAction_1_1.CanExecute(a, b : byte) : Boolean;
begin
Result := (a = 1) and (b = 1);
end;
procedure TDynamicAction_2_2.DoExecute;
begin
ShowMessage('2-2'); // Просто для демонстрации
end;
function TDynamicAction_2_2.CanExecute(a, b : byte) : Boolean;
begin
Result := (a = 2) and (b = 2);
end;3. Теперь нам надо наши классы зарегистрировать в списке: Код:
interface var DynamicActionList : TObjectList; initialization DynamicActionList := TObjectList.Create(True); TDynamicAction_1_1.Create.Register(DynamicActionList); TDynamicAction_2_2.Create.Register(DynamicActionList); finalization FreeAndNil(DynamicActionList); end. 4. Ну и последний штрих. Надо написать процедуру-выполнятель (функцию, если ничего не нашлось, то она вернет False, если что-то нашлось - то True) Код:
interface
function ExecuteDynamicAction(a,b : byte) : Boolean;
implementation
function ExecuteDynamicAction(a,b : byte) : Boolean;
var
I : Integer;
begin
Result := False;
For I := 0 To DynamicActionList.Count-1 Do
begin
Result := (DynamicActionList[i] As TDynamicActionBase).Execute(a,b);
If Result Then Break;
end;
end;ЗЫ. Если хочется действия развести по разным модулям, то тогда прямое обращение к списку действий надо заменить на использование фабрики, а описание DynamicActionList перенести в секцию implementation. DynamicActionList д.б. синглтоном. Последний раз редактировалось lmikle, 09.01.2017 в 23:17. |
|
#5
|
||||
|
||||
|
Господа, вы это серьёзно?
Почему не так? Код:
def is_passed(a, b, c, d):
if a == c and b == d:
return True
else:
return FalseДа ито, так слишком надумано, достаточно кортеж (a, b) проверить на вхождение в список кортежей возможных вариантов. Код:
>>> foo = [(1, 2), (3, 4), (5, 6)] >>> foo [(1, 2), (3, 4), (5, 6)] >>> a = (3, 4) >>> a in foo True >>> (1, 2) in foo True >>> (1, 3) in foo False З.Ы. Собственно Финн дал код той же сути, только он оперировал произведением чисел, а не кортежем. Последний раз редактировалось M.A.D.M.A.N., 10.01.2017 в 14:59. |
|
#6
|
|||
|
|||
|
Mad,
1. Изначально вопрос был в том, как не писать бесконечно длинный список if'ов. Ну и можно ли заменить его на case, если надо делать выбор по нескольким переменным. Базовый ответ - использовать хэш. Дальше я просто спроектировал чуть более гибкую системку, так, для фана. 2. Не знаю как остальные, а я просто уже начал "извращаться". Ну интересно мне было накидать макет такой маленькой подсиситемки. |
| Эти 3 пользователя(ей) сказали Спасибо lmikle за это полезное сообщение: | ||
|
#7
|
||||
|
||||
|
Снова эти вопросы из категории "как закрутить шуруп ботинком" без объяснения "зачем это нужно и нужно ли вообще на самом деле".
Если приходится прописывать СТО условий в любом виде (if или case), то с большой вероятностью задача решается в корне неверно. Например, решение "в лоб" (альтернатива решению lmikle): делаем 2 массива возможных значений A и B, и матрицу M с обработчиками размера A.length x B.length, где M[i, j] = executor при A[i] = a и B[j] = b. Если A[a] = a и B[b] = b, то решение выродится в простое взятие по индексу M[a, b]. Можно и лучше сделать, если знать, зачем все это. Но, конечно, если хочется познать дзен китайского кода - тогда согласен, вопрос "зачем" задавать нельзя. Код:
public int a(int v)
{
switch (v)
{
case 0: return 0;
case 1: return 1;
case 2: return 2;
case 3: return 3;
case 4: return 4;
// ...
case 255: return 255;
default: return -1;
}
}Последний раз редактировалось Bargest, 12.01.2017 в 00:35. |
| Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
lmikle (12.01.2017)
| ||
|
#8
|
|||
|
|||
|
Bargest,
ТС, если не ошибаюсь, хотел именно "синтаксического сахара" для выбора дейсвия по 2м переменным. Ну ему накидали вариантов. Твой вариант с этой точки зрения еще менее удачный, т.к. настройку этой матрицы замучаешься писать и потом хрен прочитаешь (через пару-тройку месяцев). А как идея - да, не хуже моего варианта и даже писать чуть меньше. Последний раз редактировалось lmikle, 12.01.2017 в 20:19. |
|
#9
|
||||
|
||||
|
[OFFTOP, продолжаем обсуждение упоротых вариантов]
Цитата:
. Сделать функцию Register(a, b, handler) и все. Решение почти совпадает с твоим, только учитывает, что по условию задачи, видимо, для каждой пары чисел не более 1 обработчика: не приходится для каждого обработчика вызыватьКод:
if CanExecute(a,b) then DoExecute(a,b); Можно построить то же самое не на двумерном массиве, а на каком-нибудь TDictionary<int, TDictionary<int, Handler>>, если в возможных значениях много неиспользуемых пар. Тогда просто вызывается handlers[a][b]() и ловится эксепшен, если обработчика нет. Короче, вариантов может быть много. Последний раз редактировалось Bargest, 12.01.2017 в 20:40. |
|
#10
|
||||
|
||||
|
Цитата:
Вариантов решения масса. Тоже хотел подкинуть идею со словарём, да подумал, что не стоит разводить флейм. З.Ы. Интересно, ТСу еще актуальна эта тема? А то от него фидбека нет. |
|
#11
|
|||
|
|||
|
Цитата:
Идею со словарем тоже смотрел. Собственно, отказался, когда понял, что попадаешь на ограничение кол-ва параметров. Да, в коде я использовал всего 2, бо как такова постановка изначального вопроса. На самом деле там д.б. Pointer или TObject (ну а для новых версий вообще дженерик), через который и будет передаваться набор параметров (а может и array of const, все зависит от задачи). Ну это если все-таки мутить в сторону библиотеки. Цитата:
Мне кажется, что ТС просто офигел от дальнейшего обсуждения и сказать уже ничего не скажет. Хотя для той постановки задачи, которая была изначально, case по хеш функции вполне достаточно. |