Пролог: Найти все номера уникальных цифр, которые могут быть сформированы из списка цифр
Вопрос
Лучшее, что я мог придумать до сих пор, это функция:
numberFromList([X], X) :- digit(X), !. numberFromList(List, N) :- member(X, List), delete(List, X, LX), numberFromList(LX, NX), N is NX * 10 + X.
куда digit/1
Является ли функция проверки, если атом является десятичной цифрой.
То numberFromList(List, N)
находит все числа, которые могут быть сформированы с все цифры из List
.
Например [2, 3] -> 23, 32
. Отказ Но я хочу получить этот результат: [2, 3] -> 2, 3, 23, 32
Я провел много часов, думая об этом, и я подозреваю, что вы можете использовать что-то вроде append(L, _, List)
В какой-то момент для получения списков меньшей длины.
Я был бы признателен за любой вклад.
Решение
Вы отсутствуете случай, когда вы пропустите цифру из списка.
numberFromList([X], X) :-
digit(X), !.
numberFromList(List, N) :-
member(X, List),
delete(List, X, LX),
numberFromList(LX, NX),
( % use X
N is NX * 10 + X
; % skip X
N = NX
).
Кстати, как упомянул @roland Illig select(X, List, LX)
заменить member(X, List), delete(List, X, LX)
Другие советы
Предикат unique/3
генерирует все списки длины до MaxLen
состоящий из символов от Symbols
. Отказ Сгенерированные списки хранятся в L
, один раз за один раз.
unique(MaxLen, Symbols, L) :-
between(0, MaxLen, Len),
length(L, Len),
unique(Symbols, L).
Помощник предикат для создания списков.
unique(_, []).
unique(Set, [H|R]) :-
select(H, Set, ReducedSet),
unique(ReducedSet, R).
Простая программа для демонстрации вышеуказанного предиката:
main :-
unique(5, [2,3], L),
write(L), nl, fail.
Вот один из способов, используя Swi-Prolog встроенные для atomic_list_concat/2
, atom_number/2
а также select/3
. Отказ Во-первых, точка входа относится к реализации с использованием изначально пустого аккумулятора:
numberFromList(L, N) :-
numberFromList(L, [], N).
Предикат numberFromList/3
Либо накапливает цифры (незаменимые) из списка, или нет, оставляя выбора точки:
numberFromList([_|Cs], Acc, N) :-
numberFromList(Cs, Acc, N).
numberFromList([C|Cs], Acc, N) :-
numberFromList(Cs, [C|Acc], N).
Окончательный пункт numberFromList/3
Разрешает накопленный список цифр и объединяет их в атом, который затем преобразуется в число по мере необходимости:
numberFromList([], [C|Cs], N) :-
permute([C|Cs], PermutedAcc),
atomic_list_concat(PermutedAcc, AN),
atom_number(AN, N).
Иногда permute/2
(как определено вручную ниже) может быть доступно в виде встроенного, такого как permutation/2
. Отказ Вот ручное определение, использующее select/3
:
permute([], []).
permute([E|Es], [E0|PL]) :-
select(E0, [E|Es], Rem),
permute(Rem, PL).
Если вы хотите список всех результатов и не хотите numberFromList/2
Чтобы отказаться от самого возвращения, вы можете обернуть звонок в numberFromList/3
(с пустым аккумулятором в первом пункте numberFromList/2
) в findall/3
вызов.