Удалить элемент из нескольких списков
У меня есть подзадача, решение которой намного больше, чем необходимо.
Проблема определяется следующим образом
Удалить X из всех групп, где группа имеет идентификатор между Y и Z или A и B
выражается как псевдопросмотр, это выглядит так с Y,Z,A,B, установленным в 0,1,3,4
remove(X,
[ period(0,1), period(3,4) ],
[
group(0, [ subgroup([_,_,X,_,_]), subgroup([X])]),
group(1, [ subgroup([X])]),
group(2, [ subgroup([_,_,X])]),
group(3, [ subgroup([_,X,_])]),
group(4, [ subgroup([X,_,_])])
], UpdatedGroups).
Результат будет
UpdatedGroups = [
group(0, [ subgroup([_,_,_,_]), subgroup([])]),
group(1, [ subgroup([])]),
group(2, [ subgroup([_,_,X])]),
group(3, [ subgroup([_,_])]),
group(4, [ subgroup([_,_])])
]
Итак, мое решение это:
Если начало текущего периода меньше или равно концу текущего периода, выполните удаление X в группах, одновременно "увеличивая" начало дня. Повторите, пока не больше периодов
Удаление X в группах выполняется путем "зацикливания" всех групп и проверки, соответствует ли он периоду, и удаляет ли он пользователя из подгрупп, что опять-таки выполняется путем "зацикливания".
Это очень утомительное, но прямое решение, теперь моя проблема в том, что я довольно часто сталкиваюсь с такими вещами и не могу найти подходов, чтобы сделать это менее всеобъемлющим способом.
Есть ли другие подходы, кроме моего, который не охватывает более 50 строк?
обновленный
Большое спасибо, код стал намного чище - он может пойти дальше, но теперь можно на самом деле опубликовать здесь (это немного изменено - но логика есть)
inPeriods(Day, [ period(Start,End) | _ ]) :- between(Start,End, Day).
inPeriods(Day, [ _ | RemainingPeriods ]) :- inPeriods(Day, RemainingPeriods).
ruleGroupsInPeriod(Periods, rulegroup(Day,_)) :- inPeriods(Day, Periods).
removeUserFromRelevantRuleGroups(UserId, Periods, RuleGroups, UpdatedRuleGroups) :-
include(ruleGroupsInPeriod(Periods), RuleGroups, IncludedRuleGroups).
exclude(ruleGroupsInPeriod(Periods), RuleGroups, ExcludedRuleGroups),
maplist(updateRuleGroup(UserId), IncludedRuleGroups, UpdatedIncludedRuleGroups)
append(UpdatedIncludedRuleGroups, ExcludedRuleGroups, UpdatedRuleGroups).
updateRuleGroup(UserId, rulegroup(X, RuleList), rulegroup(X, UpdatedRuleList)) :-
maplist(updateRule(UserId), RuleList, UpdatedRuleList).
updateRule(UserId, rule(X, UserList), rule(X, UpdatedUserList)) :-
delete(UserList, UserId, UpdatedUserList).
1 ответ
Да
Шаблон, который вы описываете, очень распространен, и все серьезные системы Prolog поставляются с мощными мета-предикатами (то есть, предикатами, чьи аргументы обозначают предикаты), которые позволяют легко гибко описать эту и многие другие распространенные ситуации, используя не более нескольких простых дополнительные определения для ваших конкретных отношений.
Предложение Ричарда О'Кифа об элементарной библиотеке Пролога содержит описания и реализации многих таких предикатов, которые становятся все более доступными во всех основных реализациях Пролога, а также в Прологе для Пролога.
В частности, вы должны изучить:
include/3
exclude/3
maplist/[2,3]
Обратите внимание, что многие из описанных предикатов нечисты в том смысле, что они разрушают декларативные свойства вашего кода. В отличие от настоящих отношений, вы не сможете использовать их во всех направлениях, сохраняя логическую обоснованность.
Упражнение: Какие из трех упомянутых выше предикатов, если таковые имеются, сохраняют логическую чистоту, когда все остальное чисто, а какие, если таковые имеются, нет?