排序不同的Java原语类型

时间:2014-03-26 22:54:58

标签: java sorting comparator

我有一个包含不同Java原语的Java集合:

List<Object> list = new ArrayList<>();
list.add(100);
list.add(10L);
list.add("KONG")
list.add(102.78);

现在我想将这些不同类型排序为“自然”顺序,就像Excel那样:

10, 100, 102.78, KONG

有没有人知道为这种类型实现Comparator的简单方法?或者是一个包装所有费力的instanceof和铸造东西的图书馆?

一个好的候选“自然”顺序首先是数字,然后是字母顺序的字符串,就像上面的例子一样。

4 个答案:

答案 0 :(得分:3)

只需将它们全部转换为字符串(使用toString(),在需要的位置框,确保正确处理null),然后对其字符串表示形式进行排序。我认为这是最简单的方法。

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.ArrayList;

public class Test53 {

    public static void main(String[] args) {
        List<Object> list = new ArrayList<Object>();
        list.add(null);
        list.add("");
        list.add(null);
        list.add("5");
        list.add(5);
        list.add("2");
        list.add(20);
        list.add(100);
        list.add(10L);
        list.add("9");
        list.add("KONG");
        list.add("KONGGG");
        list.add(102.78);
        Collections.sort(list, new SpecialComparator());
        System.out.println(Arrays.toString(list.toArray()));
    }

}

class SpecialComparator implements Comparator<Object> {

    public int compare(Object o1, Object o2) {
        if (o1 == null && o2 != null) return -1;
        else if (o1 != null && o2 == null) return 1;
        else if (o1 == null && o2 == null) return 0;

        else {
            Class<?> c1 = o1.getClass();
            Class<?> c2 = o2.getClass();

            if (Number.class.isAssignableFrom(c1) && String.class.isAssignableFrom(c2)){
                return -1;
            }else if (Number.class.isAssignableFrom(c2) && String.class.isAssignableFrom(c1)){
                return 1;
            }
            else if (Number.class.isAssignableFrom(o1.getClass()) && Number.class.isAssignableFrom(o2.getClass())){
                double d = ((Number)o1).doubleValue() - ((Number)o2).doubleValue();
                if (Math.abs(d)<1e-8) return 0;
                else return (d<0) ? -1 : 1;
            }
            else {
                return o1.toString().compareTo(o2.toString());
            }
        }
    }
}

答案 1 :(得分:1)

这是一个非常快速且非常丑陋的解决方案,它首先出现在我的脑海中 - 尽管如此,它仍然有效。所有优化都由您决定,具体取决于您想要什么,以及您将如何使用它。

import java.util.Arrays;

public class Value implements Comparable<Value> {
    private String strValue = null;
    private Double numValue = null;
    private Type   type     = null;

    private enum Type {
        NUMERIC,
        STRING;
    }

    public Value(String value) {
        this.strValue = value;
        this.type     = Type.STRING;
    }

    public Value(long value) {
        this.numValue = (double) value;
        this.type     = Type.NUMERIC;
    }

    public Value(double value) {
        this.numValue = value;
        this.type     = Type.NUMERIC;
    }

    @Override
    public int compareTo(Value cmpWith) {
        if (this.type == Type.NUMERIC && cmpWith.type == Type.NUMERIC) {
            return (int) (this.numValue - cmpWith.numValue);
        } else if (this.type == Type.NUMERIC && cmpWith.type == Type.STRING) {
            return -1;
        } else if (this.type == Type.STRING && cmpWith.type == Type.NUMERIC) {
            return 1;
        } else if (this.type == Type.STRING && cmpWith.type == Type.STRING) {
            String[] tmp = new String[]{this.strValue, cmpWith.strValue};
            Arrays.sort(tmp);

            return (tmp[0] == this.strValue) ? -1 : 1;
        }

        return 0;
    }

    public static void main(String[] args) {
        Value[] values = new Value[]{
            new Value(10), new Value(100), new Value(102.78),
            new Value("KONG"), new Value(-1), new Value("SuperKong")
        };

        Arrays.sort(values);

        for (Value val : values) {
            System.out.println((val.type == Type.NUMERIC) ? val.numValue : val. strValue);
        }
    }
}

答案 2 :(得分:1)

我喜欢这样

    String[] ss = { "100", "10", "KONG", "102.65" };
    List<String> s = Arrays.asList(ss);
    Collections.sort(s, new Comparator<String>() {

        @Override
        public int compare(String o1, String o2) {
            if (isNumber(o1)) {
                if (isNumber(o2)) {
                    // o1 = number
                    // o2 = number
                    return (Double.valueOf(o1).compareTo(Double.valueOf(o2)));
                } else {
                    // o1 = number
                    // o2 = string
                    return -1;
                }
            } else {
                if (isNumber(o2)) {
                    // o1 = string
                    // o2 = number
                    return 1;
                } else {
                    // o1 = string
                    // o2 = string
                    return o1.compareTo(o2);
                }
            }
        }

        private boolean isNumber(String s) {
            try {
                Double.parseDouble(s);
                return true;
            } catch (NumberFormatException nfe) {
                return false;
            }
        }

    });
    System.out.println(s);
}

答案 3 :(得分:0)

使用上述建议;解决方案最终非常简单:

/**
 * Compare objects of different types or int, long, float, double and string to 
 * produce an order with numbers first, then strings.
 */
public class DifferentObjectsComparator implements Comparator<Object> {

    @Override
    public int compare(Object o1, Object o2) {
        //Both strings
        if (o1 instanceof String && o2 instanceof String) {
            return o1.toString().compareTo(o2.toString());
        }
        //Both numbers
        if (o1 instanceof Number && o2 instanceof Number) {
            return Double.compare(
               ((Number) o1).doubleValue(), ((Number) o2).doubleValue()
            );
        }
        //Number then string
        if (o1 instanceof Number) {
            return -1;
        }
        //String then number
        return 1;
    }

}