ordenar objetos metodo example ejemplos colecciones java collections equals comparator

objetos - metodo compareto java



Compara dos colecciones Java usando Comparator en lugar de iguales() (4)

Planteamiento del problema

Tengo dos colecciones del mismo tipo de objeto que quiero comparar. En este caso, quiero compararlos en función de un atributo que no tenga en cuenta en equals() para los Objetos. En mi ejemplo, estoy usando colecciones clasificadas de nombres, por ejemplo:

public class Name { private String name; private int weightedRank; //getters & setters @Override public boolean equals(Object obj) { return this.name.equals(obj.name); //Naive implementation just to show //equals is based on the name field. } }

Quiero comparar las dos Colecciones para afirmar que, para la posición i en cada Colección, el weightedRank de cada Nombre en esa posición es el mismo valor. Hice algo de Google pero no encontré un método adecuado en Commons Collections ni en ninguna otra API, por lo que se me ocurrió lo siguiente:

public <T> boolean comparatorEquals(Collection<T> col1, Collection<T> col2, Comparator<T> c) { if (col1 == null) return col2 == null; if (col2 == null) return false; if (col1.size() != col2.size()) return false; Iterator<T> i1 = col1.iterator(), i2 = col2.iterator(); while(i1.hasNext() && i2.hasNext()) { if (c.compare(i1.next(), i2.next()) != 0) { return false; } } return true; }

Pregunta

Hay otra manera de hacer esto? ¿Me perdí un método obvio de Commons Collections?

Relacionado

También descubrí esta pregunta en SO, que es similar, aunque en ese caso creo que reemplazar a equals() tiene un poco más de sentido.

Editar

Algo muy similar a esto será el lanzamiento de Apache Commons Collections en un futuro cercano (en el momento de escribir este artículo). Consulte https://issues.apache.org/jira/browse/COLLECTIONS-446 .


No estoy seguro de que esta manera sea realmente mejor, pero es "otra manera" ...

Tome sus dos colecciones originales y cree otras nuevas que contengan un adaptador para cada objeto base. El adaptador debe tener .equals() y .hashCode() basados ​​en Name.calculateWeightedRank() . Luego puede usar la igualdad de colección normal para comparar las colecciones de adaptadores.

* Editar *

Usando el hashCode / equals generation estándar de Eclipse para el Adapter . Su código solo llamará adaptCollection en cada una de sus colecciones base, luego List.equals () los dos resultados.

public class Adapter { public List<Adapter> adaptCollection(List<Name> names) { List<Adapter> adapters = new ArrayList<Adapter>(names.size()); for (Name name : names) { adapters.add(new Adapter(name)); } return adapters; } private final int name; public Adapter(Name name) { this.name = name.getWeightedResult(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + name; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Adapter other = (Adapter) obj; if (name != other.name) return false; return true; } }


Podría usar la clase de Equivalence guayaba para desacoplar las nociones de "comparación" y "equivalencia". Aún tendría que escribir su método de comparación (AFAIK Guava no lo tiene) que acepte una subclase de equivalencia en lugar del comparador, pero al menos su código sería menos confuso, y podría comparar sus colecciones según los criterios de equivalencia.

El uso de una colección de objetos envueltos en equivalencia (consulte el método de ajuste en Equivalencia ) sería similar a la solución basada en el Adaptador propuesta por sharakan, pero la implementación de la equivalencia se desacoplaría de la implementación del adaptador, lo que le permite utilizar fácilmente múltiples criterios de Equivalencia.


Puede usar el nuevo método isEqualCollection agregado a CollectionUtils desde la versión 4. Este método utiliza un mecanismo de comparsion externo provisto por la implementación de la interfaz de Equator . Por favor, compruebe este javadocs: CollectionUtils.isEqualCollection(...) y Equator .


EDITAR : Se eliminó la respuesta anterior.

Otra opción que tiene es crear una interfaz llamada Weighted que podría tener este aspecto:

public interface Weighted { int getWeightedRank(); }

Luego, pida a su clase de Name implemente esta interfaz. Entonces podrías cambiar tu método para lucir así:

public <T extends Weighted> boolean weightedEquals(Collection<T> col1, Collection<T> col2) { if (col1 == null) return col2 == null; if (col2 == null) return false; if (col1.size() != col2.size()) return false; Iterator<T> i1 = col1.iterator(), i2 = col2.iterator(); while(i1.hasNext() && i2.hasNext()) { if (i1.next().getWeightedRank() != i2.next().getWeightedRank()) { return false; } } return true; }

Luego, a medida que encuentre clases adicionales que deben ser ponderadas y comparadas, puede incluirlas en su colección y también se pueden comparar entre sí. Solo una idea.