我有一个包含不同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
和铸造东西的图书馆?
一个好的候选“自然”顺序首先是数字,然后是字母顺序的字符串,就像上面的例子一样。
答案 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;
}
}