Reputation: 65
(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] ].
Upvotes: 5
Views: 3072
Reputation: 60034
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...
Upvotes: 2
Reputation: 10142
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.
Upvotes: 3