3

I need to filter the list [#,d,e,#,f,g] such that I get the output as [[d,e],[f,g]] ,
I am stuck while creating a new list every time I encounter '#' is there a way to do this? I tried the code below,

filterL([],List) :-[].
filterL([Head|Tail],X) :-
   (  Head \='#'->
      append(X,Head,List),
      filterL(Tail,List)
   ;  filterL(Tail,X)
   ).
false
  • 10,264
  • 13
  • 101
  • 209
sand
  • 183
  • 1
  • 10

3 Answers3

4

Your problem is not very well defined. Are empty sequences allowed or not? Shall [#] be related to [[],[]] (there is an empty sequence before and after) or []? You say it should be []. So:

list_splitbyhash(Xs, Xss) :-
   phrase(splitby(Xss,#), Xs).

splitby([],_E) -->
    [].
splitby(Xss,E) -->
    [E],
    splitby(Xss,E).
splitby([Xs|Xss],E) -->
    {Xs = [_|_]},
    all_seq(dif(E),Xs),
    splitby(Xss,E).

all_seq(_, []) --> [].
all_seq(C_1, [C|Cs]) -->
   [C],
   {call(C_1,C)},
   all_seq(C_1, Cs).
false
  • 10,264
  • 13
  • 101
  • 209
3

Here is another version, which uses an even more general approach:

list_splitbyhash(Xs, Xss) :-
   phrase(by_split(=(#), Xss), Xs).

=(X,X,true).
=(X,Y,false) :- dif(X,Y).

by_split(_C_2, []) --> [].
by_split(C_2, Xss) -->
   [E],
   {call(C_2,E,T)},
   (  { T = true },
      by_split(C_2, Xss)
   |  { T = false, Xss = [[E|Xs]|Xss1] },
      all_seq(callfalse(C_2),Xs),
      el_or_nothing(C_2),
      by_split(C_2, Xss1)
   ).

callfalse(C_2,E) :-
   call(C_2,E,false).

el_or_nothing(_) -->
   call(nil).
el_or_nothing(C_2), [E] -->
   [E],
   {call(C_2,E,true)}.

nil([], []).

With lambdas, this can be expressed more compactly. Instead of

   all_seq(callfalse(C_2),Xs)

and the definition for callfalse/3, one can now write

   all_seq(C_2+\F^call(C_2,F,false))
Community
  • 1
  • 1
false
  • 10,264
  • 13
  • 101
  • 209
  • 1
    Is it possible to get only one solution from the number of solutions produced by prolog predicate? For e.g..list_splitbyhash([#,1,2,3,#],X). gives only [[1,2,3]]. – sand Oct 18 '14 at 13:54
  • You are right! Fixed, even if this is no longer that nice as it used to be. – false Oct 18 '14 at 14:44
  • Thanks , I was just curious. – sand Oct 18 '14 at 15:03
  • list_splitbyhash([k,#,l,m,#,#,N],X). gives, X = [[k], [l, m], [N]], dif(N, #)., Is it possible to ignore 'dif(N,#)' from the output? – sand Oct 19 '14 at 02:43
  • @sand: That would be incorrect! Also, please look at the different answers, for there are many! – false Oct 19 '14 at 10:17
  • What if I only want the last output? Is there a way I can get it without others? For example `[A,#,B]` I'd like '[[A],[B]]'. – user3928256 Oct 24 '14 at 01:43
2

With meta-predicate splitlistIf/3 and the reified equality predicate (=)/3, the task at hand becomes a one-liner---that is both efficient and logically pure!

?- splitlistIf(=(#),[#,d,e,#,f,g],Xs).
Xs = [[d,e],[f,g]].                      % succeeds deterministically

As the code is monotone, logical soundness is ensured even for quite general queries:

?- Xs = [A,B,C], splitlistIf(=(X),Xs,Yss).
Xs = [A,B,C],     X=A ,     X=B ,     X=C , Yss = [       ] ;
Xs = [A,B,C],     X=A ,     X=B , dif(X,C), Yss = [    [C]] ;
Xs = [A,B,C],     X=A , dif(X,B),     X=C , Yss = [  [B]  ] ;
Xs = [A,B,C],     X=A , dif(X,B), dif(X,C), Yss = [  [B,C]] ;
Xs = [A,B,C], dif(X,A),     X=B ,     X=C , Yss = [[A]    ] ;
Xs = [A,B,C], dif(X,A),     X=B , dif(X,C), Yss = [[A],[C]] ;
Xs = [A,B,C], dif(X,A), dif(X,B),     X=C , Yss = [[A,B]  ] ;
Xs = [A,B,C], dif(X,A), dif(X,B), dif(X,C), Yss = [[A,B,C]].
Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166