2012-03-11 5 views
2

J'essaie de commander une liste de parents par leur âge — du plus élevé au plus bas en Prolog:Comment trier une liste d'âges dans prolog?

born(kate,date(11,2,1960)). 
born(marc,date(11,2,1961)). 
born(I,date(9,3,1962)). 
born(michel,date(24,4,1963)). 
born(harry,date(26,5,1964)). 
born(jess,date(16,1,1965)). 
born(ruth,date(26,9,1966)). 
born(fran,date(4,3,1967)). 

Le résultat devrait être une liste: [kate,marc,I,michel,harry,jess,ruth,fran].

J'essaie ce fragment de code par @CapelliC:

pairs_values([], []). 
pairs_values([_-V|T0], [V|T]) :- 
    pairs_values(T0, T). 

by_date(Sorted) :- 
    findall(Date-Person, born(Person,Date), List), 
    keysort(List, Pairs), 
    pairs_values(Pairs, Sorted). 

Mais ce code ne commande pas. Je dois le faire dans Ciao Prolog.

+2

et la raison pour laquelle le downvote est ...? –

Répondre

2

Nous pouvons le faire dans Swi-Prolog, en utilisant une commande interne:

by_date(Sorted) :- 
    findall(Date-Person, born(Person,Date), List), 
    keysort(List, Pairs), 
    pairs_values(Pairs, Sorted). 

modifier: pairs_values ​​il est vraiment simple: ici le SWI-Prolog snippet

%% pairs_values(+Pairs, -Values) is det. 
% 
% Remove the keys from a list of Key-Value pairs. Same as 
% pairs_keys_values(Pairs, _, Values) 

pairs_values([], []). 
pairs_values([_-V|T0], [V|T]) :- 
    pairs_values(T0, T). 
+0

J'essaye ceci dans "ciao prolog" mais il jette une erreur "existence erreur: procédure: utilisateur: paires_values ​​/ 2 n'existe pas" – user1257941

+0

Je dois le faire dans "ciao Prolog", je suis désolé. – user1257941

+1

Encore plus facile: 'findall (Date-P, née (P, Date), L0), keysort (L0, L1), findall (P, membre (_- P, L1), L2) .' –

2

TL; DR : La séquence que vous obtenez est triée — mais par un critère de tri auquel vous ne vous attendiez pas!

Lançons Ciao Prolog et essayons de reproduire le comportement bizarre observé par l'OP!

$ ciao 
Ciao 1.14.2-13646: Mon Aug 15 10:15:33 CEST 2011 
?- compile(dmy_vs_ymd). 
{Reading /home/stefan/Prolog/dmy_vs_ymd.pl 
WARNING: (lns 3-3) [I] - singleton variables in born/2 
} 
yes 
?- by_date(S). 
S = [fran,_,kate,marc,jess,michel,harry,ruth] ? ; 
no 

Il semble que chaque élément est mal placé — tout à fait une différence considérable :)

  • prévu: [kate,marc,I,michel,harry,jess,ruth,fran]
  • observé: [fran,_,kate,marc,jess,michel,harry,ruth]

Nous allons réorganiser les faits comme [fran,_,kate,marc,jess,michel,harry,ruth] et examiner:

 
born(fran , date(4, 03, 1967)). 
born(I  , date(9, 03, 1962)). 
born(kate , date(11, 02, 1960)).%\_______________________________________________ 
born(marc , date(11, 02, 1961)).%/ equal primary & secondary, different tertiary 
born(jess , date(16, 01, 1965)). 
born(michel, date(24, 04, 1963)). 
born(harry , date(26, 05, 1964)).%\____________________________________ 
born(ruth , date(26, 09, 1966)).%/ equal primary, different secondary 
%     ^^ ^^ ^^^^ 
%     || || |||| 
%     || || \+++------- tertiary sorting criterion 
%     || || 
%     || \+------------ secondary sorting criterion 
%     || 
%     \+------------------ primary sorting criterion 

La clé? Commande standard des termes! Citant le relevant part du Ciao Prolog manual:

Compound terms, ordered first by arity, then by the name of the principal functor, then by the arguments in left-to-right order. Recall that lists are equivalent to compound terms with principal functor '.'/2 .

Tenir compte l'objectif findall(Date-Person, born(Person,Date), List) dans la définition de by_date/1. En mettant Date avant Person en Date-Person en fait le critère principal. Pour la comparaison de deux termes composés date/3, l'ordre standard est employé.

Pour déterminer la position relative des deux date/3 composés dans l'ordre standard des termes, Prolog utilise jusqu'à trois critères:

  1. Day: Si Day est décisive, et MonthYear sont tous les deux hors de propos.

  2. Month: Si Day est indécise, mais Month est décisive, alors Year est hors de propos.

  3. Year: Seulement si Day et Month sont à la fois indécise, Year est même regardé.

So, can we solve the "sort by decreasing age" problem? And how?

Oui! Suivez ISO 8601 et migrez de date(Day,Month,Year) à date(Year,Month,Day)!

 
born(fran ,date(1967,3, 4)). 
born(I,  date(1962,3, 9)). 
born(kate ,date(1960,2,11)). 
born(marc ,date(1961,2,11)). 
born(jess ,date(1965,1,16)). 
born(michel,date(1963,4,24)). 
born(harry, date(1964,5,26)). 
born(ruth, date(1966,9,26)). 

Exemple de requête:

?- by_date(S). 
S = [kate,marc,_,michel,harry,jess,ruth,fran]. 

Hmm ... Est-ce qu'on fait encore?

  • attendu: [kate,marc,I,michel,harry,jess,ruth,fran]
  • observé: [kate,marc,_,michel,harry,jess,ruth,fran]

Pas tout à fait 100% ... I est une — variable que nous voulions en fait une constante; remplacez-le par l'atome i. Cette variable incognito était la raison pour laquelle nous avons reçu l'avertissement "singleton variable" que nous avons reçu au début de notre session Ciao Prolog. HTH!