Посоветуйте, пожалуйста, подход для реализации сложных условий с большим количеством вариантов.
Нужно реализовать метод. Что-то типа такого.
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й вариант. Осталось придумать как реализовать.
Здравствуйте, 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>Спасибо.
Здравствуйте, 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>Здравствуйте, LaptevVV, Вы писали:
LVV>>Таблицы решений — однозначно! B>Есть пример с масками\wildcards?
У меня нет, но наверное есть в базовой книжке:
Хамби Э. Программирование таблиц решений.
Болтается в сети дежавю-файл.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, 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. От того, насколько он будет сложен и насколько часто используется нужно решить будет он внешним (тогда придется писать парсер, но зато можно создать идеальнй язык) или внутренним (язык будет немного корявым, зато легко реализовать и легко интегрировать в систему).
Здравствуйте, 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
Важное дополнение:
1. Этот код очень хорошо используется повторно, т.к. спецификации нужны, например, в юнит тестах или как DTO для передачи критериев в трехзвенке (вместо DetachedCriteria в Hibernate, который таскать на клиент просто тупо).
2. Этот код хорошо генерализуется, т.к. инфраструктура для одного внутреннего DSL может пригодиться и для другого.
3. Внутренности класса-хранилища правил можно менять в целях оптимизации — если правил много, можно придумать какой-нибудь сложный алгоритм, который не будет решать задачу перебором правил.
4. Спецификацию можно подправить таким образом, чтобы она возвращала не boolean, а int — и суммировать очки, вычисляя наиболее точно подходящее правило.
Пока оставил вариант #2 — Decision Table. Удалось всё покрыть двумя таблицами.
Первая с бóльшим количеством параметров. Но для некоторых частных случаев. Если такой не найден, то вторая таблица с меньшим количеством параметров, но покрывает все возможные варианты.
Это проще чем городить паттерн матчинг для всех возможных комбинаций.
С паттерн матчинг ещё нужно было бы тест написать, чтобы быть увереным, что все возможные варианты покрыты. Да и нужной библиотеки для Java пока не нашел.
Всем спасибо за варианты, идеи и термины!
B>Смущает то что самих вариантов результата не так много. И существую пересечения. Таблицу с десятками комбинаций всё ещё не так легко поддерживать. B>Теперь думаю над таким варинтом.
Оказываеться, wildcard не так сложно реализовать. Заменить конструктор на factory, которая анализирует значения. Если значение — wildcard, то ключ клонируется в два (или более) покрывая все значения.