我有一个包含多个变量的对象列表。我想根据运行时决定的序列对此列表进行排序。我提出了以下代码,看起来效率不高。例如,如果变量不是3但是10或30,会发生什么?任何人都可以提出更好的方法吗?
import java.util.List;
import java.util.function.Function;
import static java.util.Comparator.*;
import static java.util.stream.Collectors.*;
public class SortXYZ {
double x;
String y;
double z;
public double getX() {return x; }
public String getY() {return y; }
public double getZ() {return z; }
public static void main(String[] arg) {
Function<SortXYZ, Double> f1 = SortXYZ::getX;
Function<SortXYZ, String> f2 = SortXYZ::getY;
Function<SortXYZ, Double> f3 = SortXYZ::getZ;
//could have f4, f5 etc.
List<SortXYZ> list = getList(); //get a list of SortXYZ objects
String sortSeq = arg[0];
if (sortSeq.equals("XYZ")) {
list = list.stream().sorted(comparing(f1).thenComparing(f2).thenComparing(f3)).collect(toList());
} else if (sortSeq.equals("XZY")) {
list = list.stream().sorted(comparing(f1).thenComparing(f3).thenComparing(f2)).collect(toList());
} else if (sortSeq.equals("YXZ")) {
list = list.stream().sorted(comparing(f2).thenComparing(f1).thenComparing(f3)).collect(toList());
} else if (sortSeq.equals("YZX")) {
list = list.stream().sorted(comparing(f2).thenComparing(f3).thenComparing(f1)).collect(toList());
} else if (sortSeq.equals("ZXY")) {
list = list.stream().sorted(comparing(f3).thenComparing(f1).thenComparing(f2)).collect(toList());
} else if (sortSeq.equals("ZYX")) {
list = list.stream().sorted(comparing(f3).thenComparing(f2).thenComparing(f1)).collect(toList());
}
}
}
答案 0 :(得分:4)
我暂时忽略了Comparator
中的原型。稍后会尝试提高类型安全性。
您可以创建接受比较器模式的方法,并在此基础上创建一个比较器。为了让您的生活更轻松,您还可以将吸气剂参考(f1
f2
..)存储在地图中,例如
@SuppressWarnings("rawtypes")
static Map<String, Function<SortXYZ, Comparable>> gettersMap = new HashMap<>();
static {
gettersMap.put("x", SortXYZ::getX);
gettersMap.put("y", SortXYZ::getY);
gettersMap.put("z", SortXYZ::getZ);
}
所以创建比较器的方法看起来像
@SuppressWarnings("unchecked")
static Comparator<SortXYZ> getComparator(String order){
String[] keys = order.toLowerCase().split("");
Comparator<SortXYZ> result = Comparator.comparing(gettersMap.get(keys[0]));
for (int i = 1; i<keys.length; i++){
result = result.thenComparing(gettersMap.get(keys[i]));
}
return result;
}
BTW:在您的代码中:
list = list.stream().sorted(Comparator.comparing(f3).thenComparing(f2).thenComparing(f1)).collect(toList());
您正在排序列表,并将元素写入新列表,然后再将其分配给list
引用。如果要对当前列表中的元素进行排序,只需使用
list.sort(yourComparator);
所以你的代码现在看起来更像是:
List<SortXYZ> list = getList(); //get a list of SortXYZ objects
String sortSeq = arg[0];
list.sort(getComparator(sortSeq));
答案 1 :(得分:2)
您可以使用循环迭代字符并创建比较器 - 请参阅下面的代码。
下面解决方案中的丑陋之处在于comparator
必须是#34;有效的最终&#34;,但是因为我们重新分配它需要是一个字段。更多功能解决方案是将字符流转换为函数流,然后将流减少为单个比较器,但它可能需要额外的类和基本情况的特殊处理,因此可能比下面的解决方案更多的锅炉板。
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import static java.util.Arrays.asList;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
public class SortXYZ {
private final double x;
private final String y;
private final double z;
public SortXYZ(double x, String y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double getX() {
return x;
}
public String getY() {
return y;
}
public double getZ() {
return z;
}
@Override
public String toString() {
return "SortXYZ{x=" + x + ", y=" + y + ", z=" + z + "}";
}
private static Comparator<SortXYZ> comparator;
public static void main(String[] arg) {
List<SortXYZ> list = asList(new SortXYZ(1, "A", 2), new SortXYZ(1, "A", 0), new SortXYZ(2, "B", 1));
String sortSeq = "YXZ";
comparator = comparing(function(sortSeq.charAt(0)));
sortSeq.chars().skip(1).forEach(c -> comparator = comparator.thenComparing(function((char) c)));
List<SortXYZ> sortedList = list.stream().sorted(comparator).collect(toList());
System.out.println(sortedList);
}
public static Function<SortXYZ, ? extends Comparable> function(char c) {
switch (c) {
case 'X': return SortXYZ::getX;
case 'Y': return SortXYZ::getY;
case 'Z': return SortXYZ::getZ;
default: throw new IllegalArgumentException("" + c);
}
}
}