Удалить элемент из нескольких списков

У меня есть подзадача, решение которой намного больше, чем необходимо.

Проблема определяется следующим образом

Удалить 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]

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

Упражнение: Какие из трех упомянутых выше предикатов, если таковые имеются, сохраняют логическую чистоту, когда все остальное чисто, а какие, если таковые имеются, нет?

Другие вопросы по тегам