2010-12-15 6 views
4

Je dois avoir un pet de cerveau ou quelque chose, mais je n'arrive pas à trouver une solution à cela.GNU Prolog - rechercher une liste de faits

Si vous avez une liste de faits tels que:

%country(country, population, capital) 
country(sweden, 8823, stockholm). 
country(usa, 221000, washington). 
country(france, 56000, paris). 
country(denmark, 3400, copenhagen). 

%city(city, country, population) 
city(lund, sweden, 88). 
city(new_york, usa, 5000). 
city(paris, usa, 1). 
city(copenhagen, denmark, 1200). 
city(aarhus, denmark, 330). 
city(odense, denmark, 120). 
city(stockholm, sweden, 350). 
city(washington, usa, 3400). 
city(paris, france, 2000). 
city(marseilles, france, 1000). 

Je veux trouver la deuxième plus grande ville peuplée, qui dans ce cas serait Washington, Etats-Unis avec 3400 personnes. Comment serais-tu capable de faire ça?

Merci.

+0

Comment voulez-vous trouver la plus grande ville? –

Répondre

3

Version légèrement plus courte d'une excellente réponse @ Sharky:

second_largest_city(Second) :- 
    setof(Size/City, Country^city(City,Country,Size), Cities), 
    append(_, [_/Second, _], Cities). 

setof combine findall et sort. Nous collectons Size/City paires afin qu'elles trient automatiquement la taille. La construction X^Goal introduit une variable quantifiée existentiellement X (comme ∃ x dans la logique du premier ordre).

+1

Version un peu plus courte de la version courte de larsmans: second_largest_city (Second): - setof (Taille/Ville, Pays^ville (Ville, Pays, Taille), [_, _/Second | _]). – gusbro

+0

@gusbro: nous voulons l'avant-dernier membre de 'Cities', pas le second. –

+0

ouch, vous avez raison. Ce serait second_largest_city (Second): - setof (RSize/Ville, Pays^Taille^(ville (Ville, Pays, Taille), RSize est -Size), [_, _/Second | _]). Probablement pas la peine de le faire une fois cette fois-ci ... – gusbro

4

Essayez ceci pour la taille:

second_largest_city(City) :- 
    findall(Size, city(_, _, Size), Sizes), 
    sort(Sizes, SortedSizes), 
    append(_, [Size2, _], SortedSizes), 
    city(City, _Country, Size2). 

Explication: Le findall/3 trouve la taille de tous city/3 faits, qui sont classés en ordre croissant par ordre sort/2 avec doublons supprimés. L'appel au modèle append/3 correspond à la partition de la liste triée SortedSizes en deux parties; une liste de n'importe quelle taille (_) et un reste de longueur deux ([Size2, _]) - cela lie la variable Size2 à la deuxième plus grande taille de la ville de city/3 faits. Enfin, toutes les villes de cette taille sont situées parmi city/3 faits, et sont liées à la sortie.

Note: Cela ne fonctionnera pas correctement en général si votre intégré pour sort/2n'a pas supprimer les doublons, car cela laisse la possibilité que city/3 faits avec plus d'un maximum égal renverront au maximum (plus grand) seulement. Cette implémentation utilisant append/3 pour rechercher l'avant-dernier élément de la liste triée des tailles suppose également sort/2 les numéros triés dans l'ordre croissant. Enfin, notez enfin que cela échouera complètement s'il y a moins de deux faits - mais cela est probablement correct, étant donné que le prédicat cherche la «deuxième plus grande» ville, et à strictement parler, il n'y aurait pas de un à moins qu'il y ait en effet au moins deux villes dans la DB avec des tailles différentes. Si c'est un problème, vous pouvez simplement écrire plus de clauses pour second_largest_city/1 pour gérer un tel cas.

+0

sort/2 n'est pas en ISO Prolog, mais c'est dans Edinburgh Prolog avec la sémantique que vous décrivez, qui était le fondement de la norme ISO. Ce serait bizarre pour un Prolog supportant l'ISO d'avoir une sorte/2 intégrée avec n'importe quelle autre sémantique: je suppose qu'il n'y en a pas. –

+0

@Charles: SWI, YAP et SICStus ont 'sort/2' avec la sémantique voulue. +1 pour cette réponse –

+0

@larsmans: Ils sont tous dérivés de Edinburgh Prolog. –