简体   繁体   中英

swi-prolog: how to sort list of lists by NTH element of sublist, ALLOWING DUPLICATES

(I have used 'asserta' to put a large csv file with several columns into the database.) Is there a way to sort numerically by column without removing duplicates?

As you can see from my simple example (which sorts by the second column / element), the predsort method removes duplicates.

I could work around this by switching and removing some columns and using msort, but am asking you specifically here for an alternative.

Any advice would be v much appreciated !

mycompare(X,E1,E2):- 
E1=[_,A1],E2=[_,A2],compare(X, A1, A2).

?- predsort(mycompare,[ [[95, 97], 11], [[97, 99], 4], [[97, 98], 4]],X).
X = [[[97, 99], 4], [[95, 97], 11]].

?- msort([ [[95, 97], 11], [[97, 99], 4], [[97, 98], 4]],X).
X = [[[95, 97], 11], [[97, 98], 4], [[97, 99], 4]].

%What I want is:
?- wanted_sort(...<as above>...).
X = [[[97, 98], 4], [[97, 99], 4], [[95, 97], 11] ].

The standard way to do this would be to use keysort/2 . So first you start by mapping the elements accordingly, then keysorting, and mapping back the values.

list_pairs([], []).
list_pairs([E|Es], [B-E|Ps]) :-
   E = [_,B],
   list_pairs(Es, Ps).

pairs_values([], []).
pairs_values([_-V|Ps], [V|Vs]) :-
   pairs_values(Ps, Vs).

andrew_sort(Xs, Ys) :-
   list_pairs(Xs, Ps),
   keysort(Ps, PsS),
   pairs_values(PsS, Ys).

For other uses of keysort/2 see this list .

Imho predsort /3 provides a very general and fairly efficient way to do - it's as simple as avoiding returning = from the comparison predicate. Example:

?- [user].
|: comparer(<, A, B) :- A @< B.
|: comparer(>, _, _).
(^D here)
true.

?- predsort(comparer, [1,2,1,a,b,a], L).
L = [1, 1, 2, a, a, b].

Your test case:

mycompare(<,[_,A1|_],[_,A2|_]) :- A1 < A2.
mycompare(>, _, _).

yields

?- predsort(mycompare,[ [[95, 97], 11], [[97, 99], 4], [[97, 98], 4]],X).
X = [[[97, 98], 4], [[97, 99], 4], [[95, 97], 11]].

I slightly generalized the pattern matched, from [_,N] to [_,N|_] ...

edit : it's funny, I didn't read the title ... to generalize comparing for nth argument:

?- predsort(nthcompare(2),[ [[95, 97], 11], [[97, 99], 4], [[97, 98], 4]],X).
X = [[[97, 98], 4], [[97, 99], 4], [[95, 97], 11]].

and nthcompare/4 itself:

nthcompare(N,<,A,B) :- nth1(N,A,X),nth1(N,B,Y), X @< Y.
nthcompare(_,>,_,_).

that is...

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