web-dev-qa-db-fra.com

tas avec prédicat de comparaison personnalisé

J'essaie de créer un tas avec un prédicat de tri personnalisé. Étant donné que les valeurs y entrant sont de type "défini par l'utilisateur", je ne peux pas modifier leur prédicat de comparaison intégré.

Existe-t-il un moyen de faire quelque chose comme:

h = heapq.heapify([...], key=my_lt_pred)
h = heapq.heappush(h, key=my_lt_pred)

Ou encore mieux, je pourrais envelopper les fonctions heapq dans mon propre conteneur, donc je n'ai pas besoin de continuer à passer le prédicat.

54
vsekhar

Selon la documentation heapq , la façon de personnaliser l'ordre du tas est de faire en sorte que chaque élément du tas soit un Tuple, le premier élément Tuple étant celui qui accepte la normale Python comparaisons.

Les fonctions du module heapq sont un peu lourdes (car elles ne sont pas orientées objet) et nécessitent toujours que notre objet heap (une liste heapified) soit explicitement transmis comme premier paramètre. Nous pouvons tuer deux oiseaux avec une pierre en créant une classe wrapper très simple qui nous permettra de spécifier une fonction key et de présenter le tas comme un objet.

La classe ci-dessous conserve une liste interne, où chaque élément est un Tuple, dont le premier membre est une clé, calculé au moment de l'insertion de l'élément à l'aide du paramètre key, transmis lors de l'instanciation du tas:

# -*- coding: utf-8 -*-
import heapq

class MyHeap(object):
   def __init__(self, initial=None, key=lambda x:x):
       self.key = key
       if initial:
           self._data = [(key(item), item) for item in initial]
           heapq.heapify(self._data)
       else:
           self._data = []

   def Push(self, item):
       heapq.heappush(self._data, (self.key(item), item))

   def pop(self):
       return heapq.heappop(self._data)[1]
87
jsbueno

La documentation heapq suggère que les éléments du tas pourraient être des tuples dont le premier élément est la priorité et définit l'ordre de tri.

Plus pertinent à votre question, cependant, est que la documentation comprend un discussion avec un exemple de code de la façon dont on pourrait implémenter leurs propres fonctions de wrapper heapq pour traiter les problèmes de stabilité du tri et des éléments de priorité égale (parmi autres issues).

En résumé, leur solution consiste à faire en sorte que chaque élément du tas soit un triple avec la priorité, un nombre d'entrées et l'élément à insérer. Le nombre d'entrées garantit que les éléments de même priorité sont triés dans l'ordre dans lequel ils ont été ajoutés au tas.

10
srgerg

La limite des deux réponses est qu'elles ne permettent pas de traiter les liens comme des liens. Dans le premier, les liens sont rompus en comparant les éléments, dans le second en comparant l'ordre d'entrée. Il est plus rapide de laisser les cravates être des cravates, et s'il y en a beaucoup, cela pourrait faire une grande différence. Sur la base de ce qui précède et des documents, il n'est pas clair si cela peut être réalisé dans heapq. Il semble étrange que heapq n'accepte pas de clé, contrairement aux fonctions qui en dérivent dans le même module.
P.S .: Si vous suivez le lien dans le premier commentaire ("doublon possible ...") il y a une autre suggestion de définir le fichier qui semble être une solution.

1
bbphd