对List 进行排序
如何对List
进行排序?
例:
List li = new ArrayList(); //list of numbers li.add(new Integer(20)); li.add(new Double(12.2)); li.add(new Float(1.2));
Collections.sort(li,new Comparator() { @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); } });
看看Andreas_D的 答案进行解释。在上面的代码中,处理所有空值和+无穷大值,使它们移动到最后。
更新1:
由于jarnbjo和aioobe在上面的实现中指出了一个缺陷。所以我认为最好限制Number的实现。
Collections.sort(li, new Comparator() { HashSet> allowedTypes; { allowedTypes = new HashSet>(); 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); } });
更新2:
使用guava的 约束列表 ( 不允许输入null或不支持的类型列表 ):
List li = Constraints.constrainedList(new ArrayList (), new Constraint () { HashSet> allowedTypes; { allowedTypes = new HashSet>(); 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 () { @Override public int compare(Number o1, Number o2) { Double d1 = o1.doubleValue(); Double d2 = o2.doubleValue(); return d1.compareTo(d2); } }); System.out.println(li);
正如jarnbjo在他的回答中指出的那样,没有办法正确实现Comparator
,因为Number
实例可以很好地表示大于Double.MAX_VALUE
数字(不幸的是,就Number
接口而言,我们可以“看到” “ )。 大于Double.MAX_VALUE
的Number
的示例是
new BigDecimal("" + Double.MAX_VALUE).multiply(BigDecimal.TEN)
然而,下面的解决方案处理
-
Byte
s,Short
s,Integer
s,Long
s,Float
s和Double
s -
任意大
BigInteger
s -
任意大的
BigDecimal
-
{Double, Float}.NEGATIVE_INFINITY
和{Double, Float}.POSITIVE_INFINITY
请注意,即使
BigDecimal.doubleValue
可能返回Double.NEGATIVE_INFINITY
或Double.POSITIVE_INFINITY
,它们也应始终位于任何BigDecimal
之前/之后。 -
null
元素 -
以上所有的混合物, 和
-
Number
未知实现也实现了Comparable
。(这似乎是一个合理的假设,因为标准API中的所有
Number
都实现了Comparable。)
@SuppressWarnings("unchecked") class NumberComparator implements Comparator { // 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; } }
这是一个小测试程序(这是一个ideone.com演示 ):
public class Main { public static void main(String[] args) { List li = new ArrayList (); // 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"; } } }
…打印(我删除了一些零):
-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
您需要一个null
值的解决方案,因为它们可能在集合中 – 您无法创建不带null
的对象集合。
因此,您可以检查null
并抛出IllegalArgumentException
– 带有副作用,您将无法对“污染”列表进行排序,并且必须在运行时处理这些exception。
另一个想法是将null
转换为某种数字。 通过约定将任何null
转换为Double.NaN
,我已经展示了这种方法(基于您自己的答案中的自己的解决方案)。 如果要将null
值排序到远端,您还可以考虑将它们转换为0
或Double.POSITIVE_INFINITY
或Double.NEGATIVE_INFINITY
。
Collections.sort(li,new Comparator() { @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); } });
更多的信息
这里有一些代码显示了“默认”如何处理特殊值:
Set doubles = new TreeSet (); 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);
结果(没有添加null
)是:
-Infinity 0.0 Infinity NaN
简单回答:你做不到。 专有的Number实现可能具有比通过Number接口中的实际值定义的getXXX()方法可用的更高的精度或更大的值范围。
试试我的java排序算法:
package drawFramePackage; import java.awt.geom.AffineTransform; import java.util.ArrayList; import java.util.ListIterator; import java.util.Random; public class QuicksortAlgorithm { ArrayList affs; ListIterator 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 (); 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 arrangeNumbers(ArrayList 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()); } } }