Cómo ordenar un List<Number>?

Ejemplo:

List<Number> li = new ArrayList<Number>(); //list of numbers
li.add(new Integer(20));
li.add(new Double(12.2));
li.add(new Float(1.2));

OriginalEl autor Emil | 2010-11-16

5 Comentarios

  1. 11
    Collections.sort(li,new Comparator<Number>() {
        @Override
        public int compare(Number o1, Number o2) {
            Double d1 = (o1 == null) ? Double.POSITIVE_INFINITY : o1.doubleValue();
            Double d2 = (o2 == null) ? Double.POSITIVE_INFINITY : o2.doubleValue();
            return  d1.compareTo(d2);
        }
    });

    Echar un vistazo a Andreas_D del respuesta para la explicación.En el código anterior todos los valores nulos y +Infinito de valores se controlan de tal manera que ellos pasar a la final.

    Actualización 1:

    Como jarnbjo y aioobe señala un fallo en la implementación.Así que he pensado que es mejor para restringir la implantación de Número.

    Collections.sort(li, new Comparator<Number>() {
        HashSet<Class<? extends Number>> allowedTypes;
        {
            allowedTypes = new HashSet<Class<? extends Number>>();
            allowedTypes.add(Integer.class);
            allowedTypes.add(Double.class);
            allowedTypes.add(Float.class);
            allowedTypes.add(Short.class);
            allowedTypes.add(Byte.class);
    
        }
    
        @Override
        public int compare(Number o1, Number o2) {
            Double d1 = (o1 == null) ? Double.POSITIVE_INFINITY : o1.doubleValue();
            Double d2 = (o2 == null) ? Double.POSITIVE_INFINITY : o2.doubleValue();
    
            if (o1 != null && o2 != null) {
                if (!(allowedTypes.contains(o1.getClass()) && allowedTypes.contains(o2.getClass()))) {
                    throw new UnsupportedOperationException("Allowed Types:" + allowedTypes);
                }
            }
    
            return d1.compareTo(d2);
    
        }
    });

    Actualización 2:

    Utilizando la guayaba es limitada lista (no permitir la entrada de nulo o no admitido tipo de lista):

    List<Number> li = Constraints.constrainedList(new ArrayList<Number>(),
    new Constraint<Number>() {
    HashSet<Class<? extends Number>> allowedTypes;
    {
    allowedTypes = new HashSet<Class<? extends Number>>();
    allowedTypes.add(Integer.class);
    allowedTypes.add(Double.class);
    allowedTypes.add(Float.class);
    allowedTypes.add(Short.class);
    allowedTypes.add(Byte.class);
    }
    @Override
    public Number checkElement(Number arg0) {
    if (arg0 != null) {
    if (allowedTypes.contains(arg0.getClass())) {
    return arg0;
    }
    }
    throw new IllegalArgumentException("Type Not Allowed");
    }
    }
    );
    li.add(Double.POSITIVE_INFINITY);
    li.add(new Integer(20));
    li.add(new Double(12.2));
    li.add(new Float(1.2));
    li.add(Double.NEGATIVE_INFINITY);
    li.add(Float.NEGATIVE_INFINITY);
    //li.add(null); //throws exception
    //li.add(new BigInteger("22"); //throws exception
    li.add(new Integer(20));
    System.out.println(li);
    Collections.sort(li, new Comparator<Number>() {
    @Override
    public int compare(Number o1, Number o2) {
    Double d1 = o1.doubleValue();
    Double d2 = o2.doubleValue();
    return d1.compareTo(d2);
    }
    });
    System.out.println(li);
    Tenga en cuenta que se producirá un error si el doble de los valores están demasiado lejos. Me gustaría convertir al Doble de los valores y de la llamada compareTo en ellos, o de uso mayor que/menor que la de los operadores.
    null se va a lanzar la excepción de todos modos.¿tienes una mejor idea de manejarlo ?
    Puso una condición no es así, todos los null va a ir en la final.
    Aquí es lo que yo pienso : en el compare método, comprobar si o1 y o2 son instanceof de Comparable. Si sí, entonces el código de Java ya ha implementado la mejor comparación posible para los tipos numéricos de uso que (llamando o1.compareTo(o2). Si no se implementa Comparable, yo recomendaría que trabajan fuera de la BigDecimal en lugar de Double.
    Buena pregunta +1, pero una mala respuesta, -1. Utilizar la solución que aioobe siempre – funciona, esto no!

    OriginalEl autor Emil

  2. 4

    Como jarnbjo señala en su respuesta, no hay manera de implementar un Comparator<Number> correctamente, como instancias de Number puede muy bien representar números mayores que Double.MAX_VALUE (y que, desafortunadamente, tan lejos como el Number interfaz nos permite “ver”). Un ejemplo de un Number más grande que Double.MAX_VALUE es

    new BigDecimal("" + Double.MAX_VALUE).multiply(BigDecimal.TEN)

    La solución a continuación, sin embargo, maneja

    • Bytes, Shorts, Integers, Longs, Floats y Doubles

    • Arbitraria gran BigIntegers

    • Arbitraria gran BigDecimals

    • Instancias de {Double, Float}.NEGATIVE_INFINITY y {Double, Float}.POSITIVE_INFINITY

      Tenga en cuenta que estos siempre deben venir antes de/después de cualquier BigDecimal aunque el BigDecimal.doubleValue puede devolver Double.NEGATIVE_INFINITY o Double.POSITIVE_INFINITY

    • null elementos

    • Una mezcla de todo lo anterior, y

    • Desconocido implementaciones de Number que también implementa Comparable.

      (Esto parece ser una suposición razonable ya que todos Numbers en la norma API implementa Comparable.)

     

    @SuppressWarnings("unchecked")
    class NumberComparator implements Comparator<Number> {
    //Special values that are treated as larger than any other.
    private final static List<?> special =
    Arrays.asList(Double.NaN, Float.NaN, null);
    private final static List<?> largest =
    Arrays.asList(Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
    private final static List<?> smallest =
    Arrays.asList(Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
    public int compare(Number n1, Number n2) {
    //Handle special cases (including null)
    if (special.contains(n1)) return  1;
    if (special.contains(n2)) return -1;
    if (largest.contains(n1) || smallest.contains(n2)) return  1;
    if (largest.contains(n2) || smallest.contains(n1)) return -1;
    //Promote known values (Byte, Integer, Long, Float, Double and
    //BigInteger) to BigDecimal, as this is the most generic known type.
    BigDecimal bd1 = asBigDecimal(n1);
    BigDecimal bd2 = asBigDecimal(n2);
    if (bd1 != null && bd2 != null)
    return bd1.compareTo(bd2);
    //Handle arbitrary Number-comparisons if o1 and o2 are of same class
    //and implements Comparable.
    if (n1 instanceof Comparable<?> && n2 instanceof Comparable<?>)
    try {
    return ((Comparable) n1).compareTo((Comparable) n2);
    } catch (ClassCastException cce) {
    }
    //If the longValue()s differ between the two numbers, trust these.
    int longCmp = ((Long) n1.longValue()).compareTo(n2.longValue());
    if (longCmp != 0)
    return longCmp;
    //Pray to god that the doubleValue()s differ between the two numbers.
    int doubleCmp = ((Double) n1.doubleValue()).compareTo(n2.doubleValue());
    if (doubleCmp != 0)
    return longCmp;
    //Die a painful death...
    throw new UnsupportedOperationException(
    "Cannot compare " + n1 + " with " + n2);
    }
    //Convert known Numbers to BigDecimal, and the argument n otherwise.
    private BigDecimal asBigDecimal(Number n) {
    if (n instanceof Byte)       return new BigDecimal((Byte) n);
    if (n instanceof Integer)    return new BigDecimal((Integer) n);
    if (n instanceof Short)      return new BigDecimal((Short) n);
    if (n instanceof Long)       return new BigDecimal((Long) n);
    if (n instanceof Float)      return new BigDecimal((Float) n);
    if (n instanceof Double)     return new BigDecimal((Double) n);
    if (n instanceof BigInteger) return new BigDecimal((BigInteger) n);
    if (n instanceof BigDecimal) return (BigDecimal) n;
    return null;
    }
    }

    Aquí es un pequeño programa de prueba (aquí es un ideone.com demo):

    public class Main {
    public static void main(String[] args) {
    List<Number> li = new ArrayList<Number>();
    //Add an Integer, a Double, a Float, a Short, a Byte and a Long.
    li.add(20);         li.add((short) 17);
    li.add(12.2);       li.add((byte) 100);
    li.add(0.2f);       li.add(19518926L);
    li.add(Double.NaN); li.add(Double.NEGATIVE_INFINITY);
    li.add(Float.NaN);  li.add(Double.POSITIVE_INFINITY);
    //A custom Number
    li.add(new BoolNumber(1));
    li.add(new BoolNumber(0));
    //Add two BigDecimal that are larger than Double.MAX_VALUE.
    BigDecimal largeDec = new BigDecimal("" + Double.MAX_VALUE);
    li.add(largeDec/*.multiply(BigDecimal.TEN)*/);
    li.add(largeDec.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN));
    //Add two BigInteger that are larger than Double.MAX_VALUE.
    BigInteger largeInt = largeDec.toBigInteger().add(BigInteger.ONE);
    li.add(largeInt.multiply(BigInteger.TEN));
    li.add(largeInt.multiply(BigInteger.TEN).multiply(BigInteger.TEN));
    //...and just for fun...
    li.add(null);
    Collections.shuffle(li);
    Collections.sort(li, new NumberComparator());
    for (Number num : li)
    System.out.println(num);
    }
    static class BoolNumber extends Number {
    boolean b;
    public BoolNumber(int i)    { b = i != 0; }
    public double doubleValue() { return b ?  1d :  0d; }
    public float floatValue()   { return b ?  1f :  0f; }
    public int intValue()       { return b ?   1 :   0; }
    public long longValue()     { return b ?  1L :  0L; }
    public String toString()    { return b ? "1" : "0"; }
    }
    }

    …que imprime (he quitado un par de ceros):

    -Infinity
    0
    0.2
    1
    12.2
    17
    20
    100
    19518926
    1.7976931348623157E+308
    17976931348623157000000000...00000000010
    1.797693134862315700E+310
    179769313486231570000000000000...00000100
    Infinity
    NaN
    null
    NaN
    Su aplicación es buena, pero creo que es mejor para restringir los tipos en tiempo de ejecución,ya que cualquier nueva aplicación de Número puede ser efectuado y el manejo de todos los casos en la misma comparador de no ser práctico.Además, no podemos obtener números superiores al doble del número de casos.Comprobar mi respuesta actualizada.
    Bien, usted pidió una manera de ordenar Number s, no de una manera de ordenar una mezcla de Integer, Double, Float, Short, Byte, a la derecha? Me dicen que no puede ser resuelto por completo, pero usted puede conseguir lejos. Usted dice, “Además, no podemos obtener números superiores al doble del número de casos.” Depende de si te refieres a la clase Number. (Seguro que podemos conseguir Numbers más del doble de Numbers.)
    aioobe:Sí su derecho .Le he preguntado así,pero entonces yo no era consciente de que BigInteger y BigDecimals también implementado Número.De cualquier manera gracias por tu respuesta.
    Ahora que ya sabes 🙂 y ahora usted sabe qué tan lejos se puede llegar cuando se trata de la clasificación de Numbers. Tanto nuestras soluciones puede producir un error en tiempo de ejecución cuando se alimenta con extraños Numbers, pero mi solución va a llegar un poco más que la tuya.
    aioobe: Su aplicación no necesita muy extraño Números de error. Anhela tener un una precisión mucho mayor que el doble de grandes valores, por lo que el uso de doubleValue() como una reserva se producirá a comparar por ejemplo, de Largo.MAX_VALUE y (de Largo.MAX_VALUE-1), ya que son equivalentes después de ser arrojado a doble.

    OriginalEl autor aioobe

  3. 2

    Usted necesitará una solución para null valores, porque puede estar en la colección – usted no puede crear una colección de objetos que no toma null.

    Así que usted puede comprobar para null y tirar IllegalArgumentException – con el efecto secundario, que usted no será capaz de ordenar “contaminado” listas y tienen que manejar las excepciones en tiempo de ejecución.

    Otra idea es convertir un null a algún tipo de número. He mostrado que este enfoque (basada en la propia solución de su propia respuesta) por la conversión de cualquier null a Double.NaN por la convención. También podría considerar la conversión de ellos a 0 o a Double.POSITIVE_INFINITY o Double.NEGATIVE_INFINITY si desea null valores ordenados a los extremos.

    Collections.sort(li,new Comparator<Number>() {
    @Override
    public int compare(Number o1, Number o2) {
    //null values converted to NaN by convention
    Double d1= (o1 == null) ? Double.NaN : o1.doubleValue();
    Double d2= (o2 == null) ? Double.NaN : o2.doubleValue();
    return  d1.compareTo(d2);
    }
    });

    Más Información

    Aquí un poco de código que muestra cómo los valores especiales son manejados por “default”:

    Set<Double> doubles = new TreeSet<Double>();
    doubles.add(0.);
    //doubles.add(null);   //uncommenting will lead to an exception!
    doubles.add(Double.NaN);
    doubles.add(Double.POSITIVE_INFINITY);
    doubles.add(Double.NEGATIVE_INFINITY);
    for (Double d:doubles) System.out.println(d);

    El resultado (sin null addded) es:

    -Infinity
    0.0
    Infinity
    NaN
    +1,yo tiene su punto.
    Tenga en cuenta que esta aplicación puede ver new BigDecimal("" + Double.MAX_VALUE).multiply(BigDecimal.TEN) mayor que Double.POSITIVE_INFINITY.

    OriginalEl autor Andreas_D

  4. 2

    Respuesta Simple: no Se puede. Una propiedad de un Número de aplicación puede tener una mayor precisión o un mayor rango de valor de lo que está disponible a través de la getXXX() los métodos definidos para el valor real en el Número de la interfaz.

    Puede dar un código de ejemplo para ilustrar esto ?
    No sin escribir una gran cantidad de evidente código. ¿Qué ocurre si dos el Número de casos con los valores internos “Doble.MAX_VALUE * 2” y “Doble.MAX_VALUE * 3”. Su getDouble() la aplicación debe truncar el valor de ajuste en el rango de un doble y por lo tanto, probablemente ambos devuelven el Doble.MAX_VALUE, lo que hace imposible aplicar un genérico comparador de estos tipos.
    hablando Número de instancia de BigDecimal o BigInteger ?
    Son sólo ejemplos. Cualquiera puede escribir sus propias implementaciones de el Número de la interfaz, usted no tiene que restringir su consideración a las clases en la API estándar.
    yo entiendo.Así es, hay alguna forma de restringir el acceso a cierto número de implementaciones de uso de medicamentos genéricos ?

    OriginalEl autor jarnbjo

  5. 0

    probar mi java algoritmo de ordenación:

    package drawFramePackage;
    import java.awt.geom.AffineTransform;
    import java.util.ArrayList;
    import java.util.ListIterator;
    import java.util.Random;
    public class QuicksortAlgorithm {
    ArrayList<AffineTransform> affs;
    ListIterator<AffineTransform> li;
    Integer count, count2;
    /**
    * @param args
    */
    public static void main(String[] args) {
    new QuicksortAlgorithm();
    }
    public QuicksortAlgorithm(){
    count = new Integer(0);
    count2 = new Integer(1);
    affs = new ArrayList<AffineTransform>();
    for (int i = 0; i <= 128; i++) {
    affs.add(new AffineTransform(1, 0, 0, 1, new Random().nextInt(1024), 0));
    }
    affs = arrangeNumbers(affs);
    printNumbers();
    }
    public ArrayList<AffineTransform> arrangeNumbers(ArrayList<AffineTransform> list) {
    while (list.size() > 1 && count != list.size() - 1) {
    if (list.get(count2).getTranslateX() > list.get(count).getTranslateX()) {
    list.add(count, list.get(count2));
    list.remove(count2 + 1);
    }
    if (count2 == list.size() - 1) {
    count++;
    count2 = count + 1;
    } else {
    count2++;
    }
    }
    return list;
    }
    public void printNumbers(){
    li = affs.listIterator();
    while (li.hasNext()) {
    System.out.println(li.next());
    }
    }
    }

    OriginalEl autor Nathan Nelson

Dejar respuesta

Please enter your comment!
Please enter your name here