2012-01-15 3 views
8

Actuellement j'écris une méthode compareTo pour les fonctions quadratiques sous la forme: ax^2 + bx + c. A, b, c sont des coefficients entiers qui sont transmis à la classe à travers le constructeurComment implémenter proprement les méthodes compareTo?

Dans la méthode compareTo, je suis supposé d'abord comparer les coefficients a entre deux fonctions, mais si elles sont égales, je compare les coefficients b. Si les b sont égaux, je compare les c.

La méthode que je suis venu pour cela a fini par être assez laid:

public int compareTo(QuadraticFunction other) 
{ 
    if (a > other.a) 
     return 1; 
    else if (a < other.a) 
     return -1; 
    else if (b > other.b) 
     return 1; 
    else if (b < other.b) 
     return -1; 
    else if (c > other.c) 
     return 1; 
    else if (c < other.c) 
     return -1; 
    else 
     return 0; 
} 

Je me demandais, si vous avez ces systèmes « graduées » de comparaisons (comme Comparons est avant que des b avant les c), Quelle est la meilleure façon de les mettre en œuvre? Je ne peux pas imaginer écrire une méthode comme la mienne si vous devez passer par plus de 10 variables.

Répondre

6

Pour un nombre arbitraire de coefficients (tous de même type), vous devez les stocker dans un List (ou quelque chose de similaire), plutôt que des variables membres individuellement nommées. Cela vous permet de convertir votre exemple de code en une itération.

+0

Merci pour l'aide! – CowZow

+1

Cela ne fonctionne que si toutes les variables ont le même type. –

+0

@LouisWasserman: C'est correct. Mais je pense qu'il est assez sûr de supposer que l'on représenterait des coefficients polynomiaux avec des types homogènes. –

0

Vous pouvez utiliser un idiome comme celui ci-dessous qui fractionne la comparaison en sections claires par champ, ne nécessite qu'un seul test par champ et utilise la méthode signum pour produire les valeurs de retour.

Remarque, la soustraction ci-dessous pour les œuvres int, short, char ou byte champs. Pour les champs long, float et double, vous devez utiliser des contrôles séparés pour < et == pour éviter les débordements/sous-débits et les pertes de précision dues aux arrondis. Méfiez-vous également de NaN lorsque vous comparez des valeurs à virgule flottante. Pour Comparable champs, vous pouvez simplement définir delta au résultat de compareTo après avoir utilisé des conditions distinctes pour gérer null.

long delta = ((long) a.field1) - b.field1; 
if (delta != 0) { return Long.signum(delta); } 

delta = ((long) a.field2) - b.field2; 
if (delta != 0) { return Long.signum(delta); } 

... 

return 0; 
+0

Cela ne fonctionnera correctement que si 'a.field1' et co sont au plus entiers. – Voo

+0

@Voo, vrai. L'OP dit "a, b, c sont des coefficients entiers". –

+0

Ah en lisant la question j'ai interprété "coefficient entier" dans le sens mathématique du mot, mais oui, il est probablement plus probable qu'il signifiait vraiment integer int. Pourtant, je pense qu'un gros avertissement est important lorsque l'utilisation de cet idiome est toujours en place: il a été mal utilisé pendant des décennies, donc je suis un peu méfiant avec elle. – Voo

1

Pour plus de lisibilité, et d'utiliser le intégré pour comparer les méthodes a, b, c, je factoriser à ceci:

public int compareTo(QuadraticFunction other) { 
    if (a.equals(other.a)) { 
     if (b.equals(other.b)) 
      return c.compareTo(other.c); 
     return b.comapreTo(other.b); 
    } 
    return a.compareTo(other.a); 
} 

Ce code suppose que les champs sont Number. S'il s'agit d'une primitive, convertissez-la en type enveloppé ou modifiez a.equals(b) to a == b and change a.compareTo (b) to a - b`.

Notez également que lorsqu'un if retourne, il n'y a jamais besoin d'un else - il est redondant, alors supprimez-le.

+0

On pourrait argumenter que retenir le 'else 'facilite le refactoring. Dans le cas de l'OP, il pourrait décider plus tard de changer le code en 'if (cond1) {retval = 1; } else si (cond2) {retval = -1; } else ... return retval; '. –

2

Les Guava Libraries fournissent un outil extrêmement agréable pour ce faire appelé ComparisonChain.

Votre code ressemblerait à quelque chose comme ceci:

import com.google.common.base.ComparisonChain; 
... 
public int compareTo(QuadraticFunction other) { 
    return ComparisonChain.start() 
    .compare(a, other.a) 
    .compare(b, other.b) 
    .compare(c, other.c) 
    .result(); 
} 
+0

La nouvelle API Java8 'Comparator' justifierait-elle sa propre réponse, ou devrions-nous la fusionner ici? –

Questions connexes