简体   繁体   中英

Best way to remove the first elements from each list in a list of lists in Prolog?

I am trying to remove the first element of every list in a list of lists. For example, to list [[1,2],[3,4]], I should return [[2],[4]]. In most situations, this code below will work fine:

remove_firstElem([],[]). 
remove_firstElem([[_H|T]|Ls],[T|L]) :-
    remove_firstElem(Ls,L).

But for lists like [[1],[2]], I would like it to return [] rather than [[],[]].

What I tried so far looks like:

remove_firstElem([_H|Ls],L) :-
    length(_H,1),
    remove_firstElem(Ls,L).

But it returns [ ],[[ ]],[[ ]],[[ ],[ ]] and I really don't know what's wrong with it.

Can anyone help me to fix it? Thanks for any help!

If I understand it correctly, you want to pop the head of the list, but in case the list contains only one element (or none at all), that list should be removed.

We can check if the sublist contains at least two elements with the pattern:

pop_lists([[_,H2|T]|TA],[[H2|T]|TB]) :-
    pop_lists(TA,TB).

so here we have a pattern [_,H2|T] for the first list. The _ binds with the first element, H2 with the second element, and the remaining elements with the tail.

Lists that can not unify with that pattern are the empty list, or a list with one element. So in that case we simply ignore them:

pop_lists([[]|TA],TB) :-
    pop_lists(TA,TB).
pop_lists([[_]|TA],TB) :-
    pop_lists(TA,TB).

In case we reach the end of the list, of course we unify the filter with the empty list as well:

pop_list([],[]).

we better put this clause on the first line to make our predicate more multidirectional. So in full, we have the following solution:

pop_list([],[]).
pop_list([[_,H2|T]|TA],[[H2|T]|TB]) :-
    pop_list(TA,TB).
pop_list([[]|TA],TB) :-
    pop_list(TA,TB).
pop_list([[_]|TA],TB) :-
    pop_list(TA,TB).

We can further reorder the statements, such that the amount of backtracking is less:

pop_list([],[]).
pop_list([[]|TA],TB) :-
    pop_list(TA,TB).
pop_list([[_]|TA],TB) :-
    pop_list(TA,TB).
pop_list([[_,H2|T]|TA],[[H2|T]|TB]) :-
    pop_list(TA,TB).

Easier way:

list_tail([_|Es], Es).
maplist(list_tail, Input, Output).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM