2017-02-22 5 views
0

J'ai une classe Triple qui est une classe qui peut contenir 3 entiers (x, y, z). Je souhaite remplacer les méthodes equals/hashcode afin qu'elles puissent être utilisées dans un ensemble. Donc un obj avec (1,2,3) devrait être égal à (3,2,1) ou (3,1,2) et devrait donc être égal à n'importe laquelle de ses permutations. Je sais comment faire pour une classe paire avec (x, y) - le code pour une classe de paire je pour cela est:Surcharge égale et code haché pour une classe triplet En java

class Pair { 
    int x; 
    int y; 

    public Pair(int x, int y) { 
     this.x = x; 
     this.y = y; 
    } 


    @Override 
    public boolean equals(Object obj) { 

     if(obj instanceof Pair) { 
      Pair p = (Pair) obj; 

      if (this.x == p.x && p.y == this.y || this.x == p.y && this.y == p.x) { 
       return true; 
      } 
     } 

     return false; 
    } 

    @Override 
    public int hashCode() { 
     return Integer.hashCode(x) * Integer.hashCode(y); 
    } 
} 

Cela fonctionne bien, mais si je veux l'étendre à une classe Triple , Je sais que je peux éditer la méthode d'égal à égal et ajouter plus de conditions pour vérifier mais ceci semble vraiment long. Est-ce que je peux faire ceci sans employer des bibliothèques externes dans Java?

+2

Pourquoi semble t-il vraiment de temps? – BackSlash

+0

Votre méthode égale * ne compare pas les permutations. – shmosel

+0

Cependant, voici un indice pour le rendre "plus court". Vous pourriez avoir une méthode appelée 'asList()' dans votre classe 'Triplet' qui retourne les trois éléments sous forme de liste et fait' return this.asList(). ContainsAll (other.asList()) '- Mais je pense que c'est une manière horrible de résoudre le problème. Le bon moyen est d'utiliser 'if's et de vérifier toutes les conditions nécessaires. – BackSlash

Répondre

5

Une solution est de garder un tableau trié pour la comparaison:

class Triple { 
    private final int x, y, z; 
    private final int[] sorted; 

    public Triple(int x, int y, int z) { 
     this.x = x; 
     this.y = y; 
     this.z = z; 
     this.sorted = new int[] {x, y, z}; 
     Arrays.sort(sorted); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     return obj instanceof Triple 
       && Arrays.equals(((Triple)obj).sorted, this.sorted); 
    } 

    @Override 
    public int hashCode() { 
     return Arrays.hashCode(sorted); 
    } 
} 
+0

Il peut être utile de déplacer la partie de tri à l'intérieur de la méthode 'equals'. Si l'OP va implémenter les méthodes 'setX',' setY', 'setZ', il devrait trier le tableau chaque fois que l'une de ces méthodes est appelée. Si vous déplacez le tri à l'intérieur des égaux, cela devrait rendre les choses plus légères, car vous triez une seule fois quand vous en avez besoin. – BackSlash

+2

"Si l'OP va implémenter les méthodes setX, setY, setZ", mieux vaut ne pas le faire et garder immuable "Triple" –

+1

@BackSlash Je suppose que la classe est immuable (notez les modificateurs 'final'). Si ce n'est pas le cas, vous devrez les trier à chaque appel de 'equals()' ou 'hashCode()', ce que je voudrais absolument éviter. – shmosel

0

Pour vérifier les combinaisons, vous pouvez ajouter les éléments dans list et invoquer la méthode containsAll pour vérifier l'égalité, par exemple:

public static void main(String[] args) throws IOException { 
    List<Integer> list1 = Arrays.asList(new Integer[]{1,2,4}); 
    List<Integer> list2 = Arrays.asList(new Integer[]{4,2,1}); 
    System.out.println(list1.containsAll(list2) && list2.containsAll(list1)); 
} 
0

La réponse correcte dépend de la façon dont vous voulez utiliser cette classe, si l'égalité et le hashCode doivent être peu coûteux, alors envisager d'initialiser un tableau sur la construction qui peut être facilement comparé. Quelque chose comme ceci:

import java.util.Arrays; 

public class Triple { 
    // Use this array only for hashCode & equals. 
    private final int[] values; 
    private final int x; 
    private final int y; 
    private final int z; 

    public Triple(int x, int y, int z) { 
     this.x = x; 
     this.y = y; 
     this.z = z; 
     this.values = new int[]{x, y, z}; 
     // Sort the values for simpler comparison of equality. 
     Arrays.sort(values); 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) { 
      return true; 
     } 
     if (o == null || getClass() != o.getClass()) { 
      return false; 
     } 
     Triple triple = (Triple) o; 
     return Arrays.equals(values, triple.values); 
    } 

    @Override 
    public int hashCode() { 
     return Arrays.hashCode(values); 
    } 
} 

Ajout de quelques tests pour prouver l'égalité et de l'égalité non:

import static org.hamcrest.core.Is.is; 
import static org.hamcrest.core.IsEqual.equalTo; 
import static org.hamcrest.core.IsNot.not; 

import org.junit.Assert; 
import org.junit.Test; 

public class TripleTest { 

    @Test 
    public void valuesInDifferentOrderAreEqual() { 
     Triple sortedTriple = new Triple(1, 2, 3); 
     Triple outOfOrderTriple = new Triple(3, 2, 1); 
     Assert.assertThat(sortedTriple, equalTo(outOfOrderTriple)); 
     Assert.assertThat(sortedTriple.hashCode(), is(outOfOrderTriple.hashCode())); 
    } 

    @Test 
    public void valuesInOrderAreEqual() { 
     Triple sortedTriple = new Triple(1, 2, 3); 
     Triple outOfOrderTriple = new Triple(1, 2, 3); 
     Assert.assertThat(sortedTriple, equalTo(outOfOrderTriple)); 
     Assert.assertThat(sortedTriple.hashCode(), is(outOfOrderTriple.hashCode())); 
    } 

    @Test 
    public void valuesThatAreDifferentAreNotEqual() { 
     Triple sortedTriple = new Triple(1, 2, 3); 
     Triple outOfOrderTriple = new Triple(7, 8, 9); 
     Assert.assertThat(sortedTriple, not(outOfOrderTriple)); 
     Assert.assertThat(sortedTriple.hashCode(), not(outOfOrderTriple.hashCode())); 
    } 

    @Test 
    public void valuesWithSameSumAreNotEqual() { 
     Triple sortedTriple = new Triple(11, 21, 31); 
     Triple outOfOrderTriple = new Triple(36, 12, 21); 
     Assert.assertThat(sortedTriple, not(outOfOrderTriple)); 
     Assert.assertThat(sortedTriple.hashCode(), not(outOfOrderTriple.hashCode())); 
    } 

    @Test 
    public void valuesWithSameProductAreNotEqual() { 
     Triple sortedTriple = new Triple(11, 21, 31); 
     Triple outOfOrderTriple = new Triple(33, 7, 31); 
     Assert.assertThat(sortedTriple, not(outOfOrderTriple)); 
     Assert.assertThat(sortedTriple.hashCode(), not(outOfOrderTriple.hashCode())); 
    } 
}