¿Cómo manejar la clasificación de objetos complejos?

7

¿Cómo se ordenaría una lista de objetos que tienen más de un elemento clasificable?

Supongamos que tiene un objeto simple Car y que el automóvil se define como tal:

class Car {
    public String make;
    public String model;
    public int year;
    public String color;
    // ... No methods, just a structure / container
}

Diseñé un marco simple que permitiría proporcionar múltiples SortOption s a un Sorter que luego clasificaría la lista.

interface ISorter<T> {
    List<T> sort(List<T> items);
    void addSortOption(ISortOption<T> option);
    ISortOption<T>[] getSortOptions();
    void setSortOption(ISortOption<T> option);
}

interface ISortOption<T> {
    String getLabel();
    int compare(T t1, T t2);
}

Ejemplo de uso

class SimpleStringSorter extends MergeSorter<String> {
    {
        addSorter(new AlphaSorter());
    }

    private static final class AlphaSorter implements ISortOption<String> {
        // ... implementation of alpha compare and get label
    }
}

El problema con esta solución es que no se puede expandir fácilmente. Si el auto alguna vez recibiera un nuevo campo, por ejemplo, currentOwner. Necesitaría agregar el campo, luego rastrear el archivo de clase clasificadora, implementar una nueva clase de opción de ordenación y luego volver a compilar la aplicación para la redistribución.

¿Hay una manera más fácil de expandir / práctica de ordenar datos como este?

    
pregunta ahodder 06.12.2012 - 23:03

2 respuestas

8

En realidad, puedes usar un comparador que tiene un método de comparación (a, b) que puedes implementar.

Luego puede pasarlo para el paso de comparación (esto se admite en casi todas las bibliotecas estándar de la mayoría de los idiomas).

Por ejemplo, en java puedes llamar

Collections.sort(fooList, new Comparator<Car>(){
    public int compare(Car a,Car b){
        return a.getModel().compareTo(b.getModel());
        // or compare what you want return -1, 0 or 1 
        // for less than, equal and greater than resp.
    }
});

Para ordenar sus listas según un comparador personalizado

En Java 8 hay una sintaxis lambda para crear el Comparador en una sola línea.

Esto significa que solo habrá un algoritmo de clasificación para mantener y un grupo de comparadores que pueden permanecer en la misma clase que lo que está comparando (o cerca del lugar donde se realiza la comparación).

Esto también permite una clasificación "por niveles", puede implementar algo como:

public static Comparator<T> createTieredComparator(final Comparator<? super T> comp1, final Comparator<? super T> comp2){
    return new Comparator<T>(){
        public int compare(T a,T b){
            int res = comp1.compare(a,b);
            if(res!=0)
                return res;
            else
                return comp2.compare(a,b);
        }
    };
}

Esto preferirá la comparación realizada por comp1 y solo devolverá el resultado de comp2 cuando se consideren iguales según comp1 .

    
respondido por el ratchet freak 07.12.2012 - 00:03
4

Implemente java.lang.Comparable y use colecciones como java.util.TreeSet que se basan en el "orden natural". Implementar el método compareTo () en la interfaz Comparable es muy parecido a implementar un método equals () : ese enlace contiene Un ejemplo de ambos. ¡Es crítico implementar equals () y hashcode () si implementas compareTo () y los tres deben ser compatibles entre sí!

private int compareNullHelper(Object a, Object b) {
    // sorts nulls first
    if (a == null) {
        if (b != null) { return -1; }
    } else if (b == null) { return 1; }
    return a.compareTo(b);
}

/** Sorts by make, model, year, color. */
@Override
public int compareTo(Car that) {
    // ensures consistency with equals()
    if (this.equals(that)) { return 0; }

    int ret = compareNullHelper(this.make, that.make);
    if (ret != 0) { return ret; }

    ret = compareNullHelper(this.model, that.model);
    if (ret != 0) { return ret; }

    ret = this.year - that.year;
    if (ret != 0) { return ret; }

    ret = compareNullHelper(this.color, that.color);
    if (ret != 0) { return ret; }

    // If you can't tell, return -1 which means that they are in the right
    // order but unequal - ensures consistency with equals()
    return -1;
}

Ahora puedes escribir:

Set<Car> orderedCars = new TreeSet<Car>();
orderedCars.addAll(myCars);

Si necesita clasificar de acuerdo con diferentes criterios, cree clases de Comparator adicionales (que es otra interfaz API de Java) para cada orden de clasificación. Si crea Car Implementable Comparable y el método compareTo () de su clase de Car va por marca, modelo, año, color, es posible que desee hacer un ByColorComparator implements Comparator que se compare por color, año, marca, modelo. Entonces di:

Set<Car> carsByColor = new TreeSet<Car>(new ByColorComparator());
orderedCars.addAll(myCars);

La clasificación integrada en las colecciones de Java es increíblemente rápida. Durante años, las colecciones de Java han sido una de las mejores cosas de la plataforma.

Una cosa a tener en cuenta es que esta técnica funcionará con Hibernate o JPA (si tiene una sesión de base de datos abierta) para capturar automáticamente los objetos relacionados de la base de datos que pueden ser necesarios para la clasificación.

    
respondido por el GlenPeterson 07.12.2012 - 00:02

Lea otras preguntas en las etiquetas

Comentarios Recientes

En la cuestión de una fila con dos elementos (precio) y dos listas (precio ', final y primeros.artículos), hay otro más relevante: aunque el elemento a menudo obtiene la propia columna , pero a veces el valor no tiene columna. ¿Está bien calcular más de 1000 valores? Bueno, los usuarios novatos realmente necesitan Anki 3 + .com para leer y comenzar a trabajar como principiantes. Vea aquí: <| endoftext |> Western Cowboys guardó silencio sobre la respuesta de Chelsea. Western Desert Storm comenzó el jueves pasado... Lee mas