Здравствуйте, Blazkowicz, Вы писали:
B>Приветствую!
B> Посоветуйте, пожалуйста, подход для реализации сложных условий с большим количеством вариантов. B>Нужно реализовать метод. Что-то типа такого. B>
B>public Color findDefault(boolean dark, boolean saturated, boolean positive);
B>
B>В реальности там не только булеан с двумя значениями, но и энумы по 3-4 значения. И параметров больше чем 3. B>Производительность не критичная. Важно простота понимания и модификации.
B>Тривиальный подход if..else
B>
B>Смущает то что самих вариантов результата не так много. И существую пересечения. Таблицу с десятками комбинаций всё ещё не так легко поддерживать. B>Теперь думаю над таким варинтом.
B>
B>//Инициализация
B> Color.1 = new Color("dark/*/positive");
B> Color.2 = new Color("dark/saturate/positive");
B> Color.3 = new Color("!dark/!saturate/*");
B>//Сам метод:
B> for (Color c : colors){
B> if(c.match(dark, saturate, positive)){
B> return c;
B> }
B> }
B>
B>Смущает полный перебор (хотя и не критично). Ещё как-то малой кровью надо реализовать синтаксис шаблонов. Может через regexp сделать?
B>Какое существует общепринятое решение и по каким ключевым словам гуглить?
B>Спасибо.
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, LaptevVV, Вы писали:
LVV>>Таблицы решений — однозначно! B>Есть пример с масками\wildcards?
У меня нет, но наверное есть в базовой книжке:
Хамби Э. Программирование таблиц решений.
Болтается в сети дежавю-файл.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Пока оставил вариант #2 — Decision Table. Удалось всё покрыть двумя таблицами.
Первая с бóльшим количеством параметров. Но для некоторых частных случаев. Если такой не найден, то вторая таблица с меньшим количеством параметров, но покрывает все возможные варианты.
Это проще чем городить паттерн матчинг для всех возможных комбинаций.
С паттерн матчинг ещё нужно было бы тест написать, чтобы быть увереным, что все возможные варианты покрыты. Да и нужной библиотеки для Java пока не нашел.
Всем спасибо за варианты, идеи и термины!
Здравствуйте, Blazkowicz, Вы писали:
B> Посоветуйте, пожалуйста, подход для реализации сложных условий с большим количеством вариантов. B>Нужно реализовать метод. Что-то типа такого. B>
B>public Color findDefault(boolean dark, boolean saturated, boolean positive);
B>
B>В реальности там не только булеан с двумя значениями, но и энумы по 3-4 значения. И параметров больше чем 3. B>Производительность не критичная. Важно простота понимания и модификации.
B>Тривиальный подход if..else
B>
B>Смущает полный перебор (хотя и не критично). Ещё как-то малой кровью надо реализовать синтаксис шаблонов. Может через regexp сделать? B>Какое существует общепринятое решение и по каким ключевым словам гуглить?
Я в таких случаях поступаю примерно так:
// Пример: 5 условий по 2, 2, 3, 5 и 1 бит. Итого 13 бит. Всего 8192 вариантовconst unsigned value =
((cond1 & 0x000003)) |
((cond2 & 0x000003) << 2) |
((cond3 & 0x000007) << 4) |
((cond4 & 0x00001F) << 7) |
((cond5 & 0x000001) << 12)
;
switch (value)
{
case 0x0000: case 0x0001: case 0x0002: return 1;
case 0x0003: case 0x0004: return 2;
case 0x0005: case 0x0006: case 0x0007: return 3;
// и ещё 8183 кейсов
}
На 7К вариантов я такого не делал. Но на 2048 — было дело. Текст строил кодом.
Ассемблерный код для 8192 вариантов (с default-веткой):
; 812 : switch (value)
; 813 : {
cmp eax, 8192 ; 00002000H
ja $L88942
jmp DWORD PTR $L105644[eax*4]
$L88943:
; 814 : case 0: return 0;
; 815 : case 1: return 1;
mov eax, 1
; 9008 : }
; 9009 : } // test
ret 0
$L88944:
; 816 : case 2: return 2;
mov eax, 2
; 9008 : }
; 9009 : } // test
ret 0
$L88945:
; 817 : case 3: return 3;
mov eax, 3
; 9008 : }
; 9009 : } // test
ret 0
Посоветуйте, пожалуйста, подход для реализации сложных условий с большим количеством вариантов.
Нужно реализовать метод. Что-то типа такого.
public Color findDefault(boolean dark, boolean saturated, boolean positive);
В реальности там не только булеан с двумя значениями, но и энумы по 3-4 значения. И параметров больше чем 3.
Производительность не критичная. Важно простота понимания и модификации.
Смущает то что самих вариантов результата не так много. И существую пересечения. Таблицу с десятками комбинаций всё ещё не так легко поддерживать.
Теперь думаю над таким варинтом.
//Инициализация
Color.1 = new Color("dark/*/positive");
Color.2 = new Color("dark/saturate/positive");
Color.3 = new Color("!dark/!saturate/*");
//Сам метод:for (Color c : colors){
if(c.match(dark, saturate, positive)){
return c;
}
}
Смущает полный перебор (хотя и не критично). Ещё как-то малой кровью надо реализовать синтаксис шаблонов. Может через regexp сделать?
Какое существует общепринятое решение и по каким ключевым словам гуглить?
Спасибо.
Re: Комбинации значений
От:
Аноним
Дата:
06.12.12 12:31
Оценка:
Можно попытаться ввести пространство условий, ввести меру близости, расположить на нём исходные цвета, а потом по вектору на входе определять ближайший цвет. Условия в этом случае могут быть и не булевыми типами.
Re[2]: Комбинации значений
От:
Аноним
Дата:
06.12.12 12:45
Оценка:
Если всё-таки хочется остаться с булевыми условиями, то можно завести битовые маски условий и смотреть на их пересечение.
Здравствуйте, Аноним, Вы писали:
А>Можно попытаться ввести пространство условий, ввести меру близости, расположить на нём исходные цвета, а потом по вектору на входе определять ближайший цвет. Условия в этом случае могут быть и не булевыми типами.
Пространство дискретное. И там нет очевидного правила расположения результата.
Здравствуйте, Аноним, Вы писали:
А>Если всё-таки хочется остаться с булевыми условиями, то можно завести битовые маски условий и смотреть на их пересечение.
Значения двоичные для илюстрации. Некоторые параметры могут принимать больше значений. Маска это и есть 3й вариант. Осталось придумать как реализовать.
Здравствуйте, FoolS.Top, Вы писали:
FT>Decision table?
За термин — спасибо. Но это сильно похоже на мой второй вариант. Не вижу как решается вопрос, когда некоторые условия сразу покрывают большой регион вариантов.
B>Смущает то что самих вариантов результата не так много. И существую пересечения. Таблицу с десятками комбинаций всё ещё не так легко поддерживать.
и этого: B>
B> for (Color c : colors){
B> if(c.match(dark, saturate, positive)){
B>
Т.е. задаются в списке объекты с признаками и потом в цикле (один раз, в static-блоке) строится map для ключей, типа индекс. Вдобавок можно какие-то проверки добавить, чтобы например, дубликатов не было или полное покрытие вариантов.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Blazkowicz, Вы писали:
B> Посоветуйте, пожалуйста, подход для реализации сложных условий с большим количеством вариантов. B>Какое существует общепринятое решение и по каким ключевым словам гуглить?
Таблицы решений — однозначно!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Blazkowicz, Вы писали:
B> Color.1 = new Color("dark/*/positive"); B> Color.2 = new Color("dark/saturate/positive"); B> Color.3 = new Color("!dark/!saturate/*"); B>Смущает полный перебор (хотя и не критично). Ещё как-то малой кровью надо реализовать синтаксис шаблонов. Может через regexp сделать?
Реализовать не сложно, читать — средне. Из плюсов — можно легко расширять, добавлять комбинаторы, в т.ч. использовать лямбды.
B>Какое существует общепринятое решение и по каким ключевым словам гуглить?
И добавлю очевидное: это типичный пример создания DSL. От того, насколько он будет сложен и насколько часто используется нужно решить будет он внешним (тогда придется писать парсер, но зато можно создать идеальнй язык) или внутренним (язык будет немного корявым, зато легко реализовать и легко интегрировать в систему).
Важное дополнение:
1. Этот код очень хорошо используется повторно, т.к. спецификации нужны, например, в юнит тестах или как DTO для передачи критериев в трехзвенке (вместо DetachedCriteria в Hibernate, который таскать на клиент просто тупо).
2. Этот код хорошо генерализуется, т.к. инфраструктура для одного внутреннего DSL может пригодиться и для другого.
3. Внутренности класса-хранилища правил можно менять в целях оптимизации — если правил много, можно придумать какой-нибудь сложный алгоритм, который не будет решать задачу перебором правил.
4. Спецификацию можно подправить таким образом, чтобы она возвращала не boolean, а int — и суммировать очки, вычисляя наиболее точно подходящее правило.
B>Смущает то что самих вариантов результата не так много. И существую пересечения. Таблицу с десятками комбинаций всё ещё не так легко поддерживать. B>Теперь думаю над таким варинтом.
Оказываеться, wildcard не так сложно реализовать. Заменить конструктор на factory, которая анализирует значения. Если значение — wildcard, то ключ клонируется в два (или более) покрывая все значения.
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, FoolS.Top, Вы писали:
FT>>Decision table? B>За термин — спасибо. Но это сильно похоже на мой второй вариант. Не вижу как решается вопрос, когда некоторые условия сразу покрывают большой регион вариантов.
Дык можно сделать эту таблицу с указателями — тогда эти некоторые условия будут содержать указатель на один и тот же экземпляр данных...
Здравствуйте, koandrew, Вы писали:
FT>>>Decision table? B>>За термин — спасибо. Но это сильно похоже на мой второй вариант. Не вижу как решается вопрос, когда некоторые условия сразу покрывают большой регион вариантов. K>Дык можно сделать эту таблицу с указателями — тогда эти некоторые условия будут содержать указатель на один и тот же экземпляр данных...
Я имел ввиду что-то вроде wildcards. Т.е. у меня сейчас 6 параметров. Это только с бинарными будет 64 варианта. А у меня один параметр принимает 6 значений. Это уже 196 вариантов. Причем результатов всего штук 10, поэтому все 196 комбинаций описывать нет смысла. Нужно местами использовать wildcards.
Решилось это довольно простым методом, но на Java, правда кучу дополнительного кода пришлось написать
RuleKey baseKey = new RuleKey(
p1,
p2,
p3,
enum1,
enum2,
p4);
ArrayList<RuleKey> keys;
keys = new ArrayList<uleKey>();
keys.add(baseKey);
for (Param param : Param.values()) {
if(param.value(baseKey) == Wildcard){
//Copy iterator for safe update of original listfor (RuleKey key : new ArrayList<RuleKey>(keys)) {
keys.remove(key);
keys.addAll(param.applyWildcard(key));//Здесь параметр, перебирает все возможные варианты своего значения и создаёт копии baseKey, со всеми возможными вариантами вместо wildcard
}
}
}
for (RuleKey key : keys) {
decisionMap.put(key, rule);
}