我目前有一个代码段,该代码段以升序返回列表的字符串:
df2 <- df %>%
group_by(Date = as.Date(datetime)) %>%
mutate(Fn = F[hour(datetime) == 0]),
z = (Fn - F)/Fn) %>%
ungroup() %>%
select(-Date)
虽然可行,但我想向订单中添加一些自定义“规则”,以便将某些字符串放在最前面。例如:
Collections.sort(myList, new Comparator<MyClass>() {
@Override
public int compare(MyClass o1, MyClass o2) {
return o1.aString.compareTo(o2.aString);
}
});
是否可以使用这样的if(aString.equals("Hi")){
// put string first in the order
}
if(aString begins with a null character, e.g. " ") {
// put string after Hi, but before the other strings
}
// So the order could be: Hi, _string, a_string, b_string, c_string
自定义列表的排序?
答案 0 :(得分:3)
有可能。
您可以将函数传递给Comparator.comparing
方法以定义您的规则。请注意,我们只返回整数,这是应该排在最前面的元素的最低整数。
Comparator<MyClass> myRules = Comparator.comparing(t -> {
if (t.aString.equals("Hi")) {
return 0;
}
if (t.aString.startsWith(" ")) {
return 1;
}
else {
return 2;
}
});
如果您希望其余元素按字母顺序排序,那么如果您的类实现了thenComparing(Comparator.naturalOrder())
,则可以使用Comparable
。否则,您应该首先提取排序键:
Collections.sort(myList, myRules.thenComparing(Comparator.comparing(t -> t.aString)));
请注意,返回的实际特定数字并不重要,重要的是排序时,较低的数字位于较高的数字之前,因此,如果始终将字符串“ Hi”放在首位,则对应的数字应该是返回的最低数字(在我的情况下为0)。
如果您无法使用Java 8功能,则可以这样实现:
Comparator<MyClass> myRules = new Comparator<MyClass>() {
@Override
public int compare(MyClass o1, MyClass o2) {
int order = Integer.compare(getOrder(o1), getOrder(o2));
return (order != 0 ? order : o1.aString.compareTo(o2.aString));
}
private int getOrder(MyClass m) {
if (m.aString.equals("Hi")) {
return 0;
}
else if (m.aString.startsWith(" ")) {
return 1;
}
else {
return 2;
}
}
};
并这样称呼它:
Collections.sort(list, myRules);
其工作原理如下:首先,两个接收到的字符串都映射到您的自定义规则集,并相互减去。如果两者不同,则操作getOrder(o1) - getOrder(o2)
确定比较。否则,如果两者都相同,则将按照人脑学顺序进行比较。
答案 1 :(得分:3)
MC Emperor的answer非常好(+1),因为它满足了OP不使用Java 8 API的要求。它还使用整洁的内部函数技术(getOrder
方法)将条件映射到较小的整数值,以进行第一级比较。
这是使用Java 8构造的替代方法。假设MyClass
有一个getString
方法可以完成明显的工作。
Collections.sort(myList,
Comparator.comparing((MyClass mc) -> ! mc.getString().equals("Hi"))
.thenComparing(mc -> ! mc.getString().startsWith(" "))
.thenComparing(MyClass::getString));
这是不透明的,直到您习惯了这种样式。关键的见解是,提供给Comparator.comparing
和Comparator.thenComparing
的“提取器”功能通常只是提取一个字段,但是它可以是对任何其他值的一般映射。如果该值是可比较的,则不需要提供其他比较器。在这种情况下,提取器函数是布尔表达式。这被装箱成一个布尔值,事实证明它是可比较的。由于false
在true
之前排序,因此我们需要对布尔表达式求反。
还请注意,我必须为lambda参数提供一个显式的类型声明,因为类型推断通常不适用于诸如此类的链式比较器情况。
答案 2 :(得分:0)
是的,有可能,您可以完全控制compareTo()方法。两件事:
一种实现某些事物的具体方式,其中某些单词总是最先出现而某些单词总是最末尾,并且在例外之间定义了顺序:
Map<String, Integer> exceptionMap = new HashMap<>();
exceptionMap.put("lowest", -2);
exceptionMap.put("second_lowest", -1);
exceptionMap.put("second_highest", 1);
exceptionMap.put("highest", 2);
public int compareToWithExceptionMap(String s1, String s2) {
int firstExceptional = exceptionMap.getOrDefault(s1, 0);
int secondExceptional = exceptionMap.getOrDefault(s2, 0);
if (firstExceptional == 0 && secondExceptional == 0) {
return s1.compareTo(s2);
}
return firstExceptional - secondExceptional;
}