1

I have a number, let's say 123, and I want to generate a set of all the possible ways to split it:

[[1, 23], [12, 3], [1, 2, 3]].

I have thought of creating the powerset of [1,2,3]:

?- findall(Powerset, powerset([1,2,3], Powerset), Z).
Z = [[1], [1, 2], [1, 2, 3], [2], [2, 3], [3]].

then combining the sets together and checking with append/3 if their concatenation is the initial set [1,2,3], i.e

[[1], [2, 3]] -> [1, 23]
[[1, 2], [3]] -> [12, 3]
[[1], [2], [3]] -> [1, 2, 3]

Do you think of another simpler (more elegant) solution?

I use this predicate from gnu Prolog powerset modification

powerset(L, [H|T]):-
  append([H|T], _, L).
powerset([_|L], P):-
  powerset(L, P).
Community
  • 1
  • 1
pantelis300
  • 439
  • 4
  • 9

2 Answers2

2

No need to use findall/3 here---use !

int_split(X) -->
   int_split__aux(X,10,[]).

int_split__aux(X,P,Ds) -->
   (  { X =:= 0 }
   -> [Ds]
   ;  { X < P }
   -> [[X|Ds]]
   ;  { X0 is X mod P,
        X1 is X div P },
      int_split__aux(X1,10,[X0|Ds]),
      { P1 is P*10 },
      int_split__aux(X,P1,Ds)
   ).

Sample use:

?- phrase(int_split(123),Zss).
Zss = [[1,2,3], [12,3], [1,23], [123]].

?- phrase(int_split(1234),Zss).
Zss = [[1,2,3,4], [12,3,4], [1,23,4], [123,4], [1,2,34], [12,34], [1,234], [1234]].
repeat
  • 18,496
  • 4
  • 54
  • 166
2

instead of powerset, we could have a more focused predicate

parts(C, [C]).
parts(L, Ps) :-
    append(H, T, L), H \= [], T \= [],
    parts(T, Ts),
    append([H], Ts, Ps).

and now

?- number_codes(123,Cs),parts(Cs,Ps),maplist(number_codes,Ns,Ps).
Cs = [49, 50, 51],
Ps = [[49, 50, 51]],
Ns = [123] ;
...etc...

so we can collect interesting Ns with findall

?- findall(Ns,(number_codes(123,Cs),parts(Cs,Ps),maplist(number_codes,Ns,Ps)),Rs).
Rs = [[123], [1, 23], [1, 2, 3], [12, 3]].
CapelliC
  • 59,646
  • 5
  • 47
  • 90