2
votes

Comment fonctionne Comparator.compare ()?

En apprenant Kotlin, j'essaie de comprendre comment Java L'interface du comparateur fonctionne - principalement la fonction compare () pour que je puisse l'utiliser.

J'ai essayé de lire la documentation pour compare () mais j'aimerais une explication beaucoup plus simple de son fonctionnement.

Que signifient exactement x et y dans compare (x, y) lors d'une itération sur une liste? Cible et compare-t-il chaque paire de nombres lors de l'itération? Par exemple:

import java.util.*

fun getList(): List<Int> {
    val arrayList = arrayListOf(1, 5, 2)
    Collections.sort(arrayList, object: Comparator<Int> {
        override fun compare(x: Int, y: Int){
            return x < y
        }
    } )
    return arrayList

comparerait-il 1 et 2 (x et y), puis 2 et 3 (x et y), puis 3 et 4 (x et y)?

J'ai une fonction Kotlin qui fournit un comparateur pour trier une liste dans un ordre décroissant:

arrayOf(1, 2, 3, 4)

Je ne sais pas pourquoi la fonction ci-dessus n'est pas Ce n’est pas la bonne syntaxe pour compléter cela.


1 commentaires

... l'exemple que vous avez montré est plutôt la manière Java de le faire. Vous pouvez jeter un œil à sortWith (combiné avec < code> compareBy ) ou sortBy . Ou jetez un œil à Commande de collection Kotlin


4 Réponses :


3
votes

Un Comparator est simplement un moyen de comparer 2 éléments quelconques de type T.

Que sont exactement x et y dans compare (x, y) lors d'une itération sur une liste?

Lors de l'itération, le comparateur n'est pas du tout appelé.

Lorsqu'il est passé à la méthode Collections.sort () , le comparateur est utilisé chaque fois que l'algorithme de tri sous-jacent a besoin de comparer 2 éléments.

Je ne sais pas pourquoi la fonction ci-dessus n'est pas la bonne syntaxe pour compléter cela.

Votre implémentation actuelle ne satisfait pas la documentation . compare () doit renvoyer un entier négatif, 0, ou un entier positif en fonction de la relation entre 2 éléments.


0 commentaires

5
votes

Cela se résume à cette déclaration du javadoc :

Compare ses deux arguments d'ordre. Renvoie un entier négatif, zéro ou un entier positif car le premier argument est inférieur, égal ou supérieur au second.

C'est tout ce qu'il y a à faire. Lorsque vous rédigez un comparateur, vous définissez l’ordre que vous souhaitez. L'essentiel est que votre méthode renvoie -1, 0 ou 1. Selon la manière dont vous voulez , ces deux arguments entrants doivent être classés. (et oui, il n'a pas besoin de -1 ou 1, juste négatif, zéro, positif).

En d'autres termes: le point clé est que compare () sert dans ce contrat. Il définit une commande sur deux éléments. C'est tout ce qu'il y a à faire.

Lors du tri des données, il sera appelé à chaque fois que le code de tri sous-jacent a besoin de connaître l'ordre de deux éléments. Ainsi, "l'ordre" exact dans lequel ces appels ont lieu et les arguments passés dépendent de l'algorithme de tri réel et des données que vous avez l'intention de trier.

De ce point de vue, votre question implique que vous réfléchissez un peu à tout le sujet. Comprenez simplement: vous utilisez un comparateur lorsque vous avez l'intention de définir un ordre "personnalisé" pour vos objets / valeurs.

Et il n'y a aucun sens à définir votre "propre" comparateur pour int, Int ou Integer, car ces classes définissent déjà leur ordre naturel, il existe donc déjà Integer.compare () par exemple. Le seul cas d'utilisation pour définir votre propre comparateur pour une telle classe serait lorsque vous souhaitez les ordonner différemment. Mais il est fort probable que vous utilisiez toujours la fonctionnalité de comparateur existante et utiliseriez d'autres méthodes intégrées, par exemple pour inverser l'ordre "naturel".


8 commentaires

Notez que bien qu'à proprement parler, renvoyer une valeur positive ou négative est acceptable, la convention est de renvoyer 1 et -1 lorsque cela est possible.


@biziclop a adapté la réponse en conséquence.


Oh, j'avais l'impression que le tri était plus flexible. Est-ce simplement: positif = croissant, négatif = décroissant?


@Zorgan Encore une fois: le tri est uniquement basé sur l'ordre. Vous définissez l’ordre à utiliser. Renvoie un entier négatif, zéro ou un entier positif car le premier argument est inférieur, égal ou supérieur au second. Par ordre croissant, 5 est inférieur à 10, donc "négatif". Si vous voulez descendre, 5 doit être ordonné APRÈS 10, donc positif. J'espère que cela a du sens.


Mais vous ne pouvez pas choisir comment «classer» les numéros - il ne s'agit que de x et y à partir d'une liste inconnue? @GhostCat


@Zorgan Le tri d'une liste est basé sur l'application du MÊME ordre pour n'importe quel x, y, z de cette liste. Si x


Merci @GhostCat J'avais une vision faussée de ce qu'était le "tri" - c'est logique. Cependant je ne comprends pas ce qui se passe après la première comparaison. Disons que je fais une sorte ascendante de listOf (2, 5, 1, 9) - 2..compareTo (5) renverra évidemment -1 donc il n'y a pas d'échange. Mais que se passe-t-il ensuite? 5 et 1 échangeront parce que 5 est supérieur à 1 - cependant 2 est supérieur à 1 mais est bloqué en tant que premier élément.


C'est ce que j'ai écrit dans ma réponse: cela dépend de l'algorithme de tri. Et vous avez raison: les éléments peuvent être comparés plusieurs fois jusqu'à ce qu'ils «atteignent» leur destination finale. Alors: étudiez le fonctionnement du tri ... visualgo.net/bn/sorting . Au-delà de cela: j'espère que nous arriverons bientôt à une clôture, car avoir des discussions prolongées n'est pas ce à quoi ce site est destiné. Votre problème de base est cette vue biaisée du tri, et vous pouvez y remédier en apprenant comment fonctionnent les différents algorithmes de tri.



2
votes

La documentation de compare est assez claire:

renvoie un entier négatif, zéro ou un entier positif comme premier l'argument est inférieur, égal ou supérieur au second.

Vous devez donc renvoyer un Int de votre fonction plutôt qu'un booléen.

Pour fournir un code Kotlin fonctionnel, j'inclus un exemple: p >

val list = listOf(1, 5, 2)
list.sortedWith(Comparator { x, y ->
       x.compareTo(y)
})

Le tri lui-même peut être effectué avec différents algorithmes mais ils utiliseront compareTo en interne. La documentation Collections donne une idée:

La documentation des algorithmes polymorphes contenus dans ce class comprend généralement une brève description de l'implémentation. Ces descriptions devraient être considérées comme des notes de mise en œuvre, plutôt que des parties de la spécification. Les réalisateurs doivent se sentir libres de remplacer d'autres algorithmes, tant que la spécification elle-même est adhérant à. (Par exemple, l'algorithme utilisé par sort n'a pas à être un tri fusionné, mais il doit être stable.)


0 commentaires

1
votes

Comparator est uniquement une interface pour les classes qui peuvent être comparées. Il s'agit de comparer N'IMPORTE QUEL deux objets. Ni plus ni moins. À partir de la documentation:

@param o1 le premier objet à comparer.

@param o2 le deuxième objet à comparer.

@return un entier négatif, zéro ou un entier positif comme premier argument est inférieur, égal ou supérieur au seconde.

Le tri est une autre chose. Il utilise un comparateur (il serait difficile de trier quoi que ce soit sans savoir comment comparer deux éléments), vous pouvez donc fournir votre propre façon de trier la collection.

Mais comment est-il trié? Tout ce que nous savons sur le tri via Collections.sort (collection, comparateur) , c'est que le tri est stable. En savoir plus sur le tri: https://www.geeksforgeeks.org/sorting-algorithms/


0 commentaires