简体   繁体   中英

Prolog merge two lists

I need to merge two lists in Prolog. On input should be predicate merge/3 .

视觉提示

Should work like this:

?- merge([6,4,b,8], [5,b,s,6], X).
X = [6, 4, b, 8, 5, s].

What I have tried:

%rules
merge(A, B, X):- 
    merge(A, B, B, X).

merge([], X, _, X).
merge([Head|L1], [Head|L2], Tmp, [Head|X]) :-
    merge(L1, L2, Tmp, X),
    !.
merge(L1, [_|L2], Tmp, X) :-
    merge(L1, L2, Tmp, X),
    !.
merge([A|L1], [], Tmp, [A|X]) :-
    merge(L1, Tmp, Tmp, X),
    !.

What I get:

?- merge([1,2,a,3], [5,d,a,1], X).
X = [1, 2, a, 3, 5, d, a, 1].

What I expect:

?- merge([1,2,a,3], [5,d,a,1], X).
X = [1, 2, a, 3, 5, d].

If the order of the elements does not somehow depend on the order of the two input lists, this is an idiomatic Prolog solution:

?- append([6,4,b,8], [5,b,s,6], A), sort(A, B).
A = [6, 4, b, 8, 5, b, s, 6],
B = [4, 5, 6, 8, b, s].

If the order is important, you need to explain how exactly.

And some comments on the code you show. The names that you have chosen for your predicates: both "join" and "merge" have well-established meanings different from what you seem to be attempting to achieve ("join" as in relational databases, "merge" as in "merge two ordered lists"). What you are doing is rather a "union" (and by the way, click on this link and read the code!).

Also, it is almost always a mistake (not an error, but a mistake) to have a cut as the last subgoal of a clause body. Having multiple clauses to a predicate that are not obviously mutually exclusive (as the last 3 of the 4 clauses to your merge/4 ) is commonly a design flaw (not a mistake).

This can be done by rewriting built-in predicates ! eg :

my_append([], R, R) .
my_append([H|T], R1, [H|R2]) :-
    my_append(T, R1, R2).


my_member(H, [H|_]).
my_member(H, [_|T]) :-
    my_member(H, T).

So, I can say that merging L with an empty list gives this list L

merge(L, [], L).

Now, to merge two lists, I look at the first element of the second list.

If it is in the first list, I ignore it and I merge the first list, with the rest of the second.

If not, I add this first element at the end of the first list and I merge the new first list with the rest of the second.

I must say that it's not very efficient !!

merge(L, [H| T], R) :-
    (   my_member(H, L)
    ->  merge(L, T, R)
    ;   my_append(L, [H], L1),
        merge(L1, T, R)).

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