3

I have list of lists like this:

[[q, ,w, ,e, ,r, ,t, ,z],[a, ,s, ,d, ,f, ,g, ,h],[y, ,x, ,c, ,v, ,b, ,n]]

and I need to delete all spaces except in last list. So I want:

[[q,w,e,r,t,z],[a,s,d,f,g,h],[y, ,x, ,c, ,v, ,b, ,n]]

I tried:

deleteAll([_|[]],[]).
deleteAll([Head|Tail],L) :-
  deleteAll(Tail,_),
  subtract(Head,[ ],L).

But it doesnt work. I'm getting onlny:

[q, ,w, ,e, ,r, ,t, ,z]

So it seems that even subtract didnt match the [ ] as space. How can I achieve this?

lindaon
  • 147
  • 2
  • 8

4 Answers4

3

As @false already pointed out [ ] is not a space but the empty list. Also your predicate is describing L as Head minus the empty list, and it doesn't care about the result of the recursion (deleteAll(Tail,_)). That's why you get the unaltered first list as result.

Think about what the predicate should describe: a relation between two lists of lists where the second list contains the sublists of the first list without space, except the very last sublist, that is unaltered:

:- set_prolog_flag(double_quotes, chars).

lists_withoutspace([X],[X]).                    % last list unaltered
lists_withoutspace([H1,H2|T1],[H1WoS|T2]) :-    % H1Wos:
   list_withoutspace(H1,H1WoS),                 % first sublist without spaces
   lists_withoutspace([H2|T1],T2).              % the same for the rests

For list_withoutspace/2 you could use te built-in predicate char_type/2 to determine the type of the first list-element:

list_withoutspace([],[]).          % empty list contains no space
list_withoutspace([X|T],L) :-      % X is not in the list
   char_type(X,space),             % if it is space
   list_withoutspace(T,L).         % relation must also hold for tail
list_withoutspace([X|T],[X|L]) :-  % X is in the list
   char_type(X,alpha),             % if it is a letter
   list_withoutspace(T,L).         % relation must also hold for tail

If you want to match more than letters change alpha accordingly. If you query this predicate, you get the desired result:

   ?- lists_withoutspace([[q,' ',w,' ',e,' ',r,' ',t,' ',z],[a,' ',s,' ',d,' ',f,' ',g,' ',h],[y,' ',x,' ',c,' ',v,' ',b,' ',n]],L).
L = [[q,w,e,r,t,z],[a,s,d,f,g,h],[y,' ',x,' ',c,' ',v,' ',b,' ',n]] ? ;
no

Or more compactly:

   ?- lists_withoutspace(["q w e r t z","a s d f g h","y x c v b n"],L).
L = [[q,w,e,r,t,z],[a,s,d,f,g,h],[y,' ',x,' ',c,' ',v,' ',b,' ',n]] ? ;
no
tas
  • 8,100
  • 3
  • 14
  • 22
  • 2
    s(X). Bonus question: how can I find out / test automatically (without reading all the documentation) which built-in / library predicates are pure enough for my taste? – repeat Oct 29 '17 at 08:02
  • 2
    @repeat: I'd probably try the two characterisations in the tag-info of [tag:logical-purity]. In this case char_type/2 (I assume that's the built-in you refer to) succeeds if one argument is instantiated but the generalisation, the most general query, leads to an instantiation error. However, the way I use it the second argument is always `space` and using it that way doesn't break commutativity of conjunction, e.g. `?- X=' ', char_type(X,space).` and `?- char_type(X,space), X=' '.` yield the same result. In this case that's good enough for me. – tas Oct 29 '17 at 20:34
  • 1
    Thx 4 Ur reply! Sounds good to me... just wondering how to check this out automatically, to aid the programmer / coder / user / myself with seeing the boundaries between the pure and impure. – repeat Oct 29 '17 at 21:10
  • 2
    It's high time to implement `predicate_algebraicproperties/2` ;) maybe with a little help using annotations like "I promise `memberd/2` is pure"... what's your take on this? – repeat Oct 29 '17 at 21:11
  • 2
    If it doesn't exist, we should make it. Seriously! The way I see it: (1) both pure and impure code could profit, (2) it would fit nicely with meta-predicates (e.g., `maplist/3` is pure if its first arg is pure), (3) we could only win, because of "lowered expectations", (4) it burns a lot of processor cycles and hopefully points to some insights. – repeat Oct 29 '17 at 21:49
3
:- set_prolog_flag(double_quotes, chars).
:- use_module(library(double_quotes)).

spdels([], []).
spdels([Cs], [Cs]).
spdels([Cs|Css], [Ds|Dss]) :-
   Css = [_|_],
   Dss = [_|_],
   text_nospaces(Cs, Ds),
   spdels(Css, Dss).

text_nospaces([], []).
text_nospaces([C|Cs], Ds0) :-
   if_(C = ' ', Ds0 = Ds1, Ds0 = [C|Ds1] ),
   text_nospaces(Cs, Ds1).


text_nospaces_bis(Cs, Ds) :-
   tfilter(dif(' '), Cs, Ds).

using if_/3 and tfilter/3.

?- spdels(["a b c","d e","f g"], Cs).
   Cs = ["abc","de","f g"]
;  false.
false
  • 10,264
  • 13
  • 101
  • 209
3

Why not delegate the "recursive part" to Prolog library predicates?

Based on tfilter/3 and dif/3 define spaces_gone/2 like so:

:- use_module(library(lists), [same_length/2, reverse/2, maplist/3]).

spaces_gone([], []).
spaces_gone([A|As], [D|Ds]) :-
   same_length(As, Ds),
   reverse([A|As], [Last|Bs]),
   maplist(tfilter(dif(' ')), Bs, Cs),
   reverse([Last|Cs], [D|Ds]).

Sample query using SICStus Prolog 4.3.2:

| ?- set_prolog_flag(double_quotes, chars),
     use_module(library(double_quotes)).
% ...
yes

| ?- spaces_gone(["a b c","d e","f g"], Css).
Css = ["abc","de","f g"] ? ;
no
Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166
0

code :

deleteAllSpaces_except_last([X],[X]):-!.                % without last Element

deleteAllSpaces_except_last([[]|Ys],[[]|Ys1]):-         % End of List inside List_of_lists
        deleteAllSpaces_except_last(Ys,Ys1).

deleteAllSpaces_except_last([[X|Xs]|Ys],Res):-          % if X=' ' then skip else add into New list inside list_of_lists
        (X=' ',Res=[Xs1|Ys1];Res=[[X|Xs1]|Ys1]),
        deleteAllSpaces_except_last([Xs|Ys],[Xs1|Ys1]).

test :

| ?- deleteAllSpaces_except_last([[q,' ',w,' ',e,' ',r,' ',t,' ',z],[a,' ',s,' ',d,' ',f,' ',g,' ',h],[y,' ',x,' ',c,' ',v,' ',b,' ',n]],L).
L = [[q,w,e,r,t,z],[a,s,d,f,g,h],[y,' ',x,' ',c,' ',v,' ',b,' ',n]] ? ;
no

| ?- deleteAllSpaces_except_last([[q,' ',w,' ',e,' ',r,' ',t,' '],[],[y,' ',x,' ',c,' ',v,' ',b,' ',n]],L).
L = [[q,w,e,r,t],[],[y,' ',x,' ',c,' ',v,' ',b,' ',n]] ? 
Ans Piter
  • 573
  • 1
  • 5
  • 17