最近在开发中,重构背包功能时,需要对物品进行多级排序。
用传统的Java语法很难实现,所以写了个函数式比较器,特点有
- 支持链式分级排序
- 支持正序、逆序排
- 支持按条件移动(前移后移)
下面给个简单例子
public static void main(String[] args) {
List employeeList = Arrays.asList(
Employee.builder().id(101).name("Matt").gender("male").salary(5000).office("New York").build(),
Employee.builder().id(102).name("Sheila").gender("female").salary(6000).office("London").build(),
Employee.builder().id(103).name("Carrie").gender("male").salary(20000).office("New York").build(),
Employee.builder().id(104).name("Hannah").gender("female").salary(7000).office("New York").build(),
Employee.builder().id(105).name("Pat").gender("male").salary(8000).office("London").build(),
Employee.builder().id(106).name("Elin").gender("female").salary(29000).office("Shanghai").build()
);
Collections.sort(employeeList,
//男性移动到下面
ComparatorPlus.moveBack( x -> "male".equals(x.getGender()))
//"New York"的往前排
.thenMoveForward(x -> "New York".equals(x.getOffice()))
//再按 薪水倒排
.thenReversedComparing(Employee::getSalary)
);
System.out.println("----");
employeeList.forEach(System.out::println);
}
output:
Employee(id=104, name=Hannah, gender=female, salary=7000, office=New York)
Employee(id=106, name=Elin, gender=female, salary=29000, office=Shanghai)
Employee(id=102, name=Sheila, gender=female, salary=6000, office=London)
Employee(id=103, name=Carrie, gender=male, salary=20000, office=New York)
Employee(id=101, name=Matt, gender=male, salary=5000, office=New York)
Employee(id=105, name=Pat, gender=male, salary=8000, office=London)
最后,附上比较器源码
import java.io.Serializable;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* 增强排序器,支持逆向排序和条件移动
* Created by adam.zh on 2018/1/20
*/
@FunctionalInterface
public interface ComparatorPlus extends Comparator {
@Override
int compare(T o1, T o2);
public static > ComparatorPlus comparing(
Function super T, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (ComparatorPlus & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
public static > ComparatorPlus reversedComparing(
Function super T, ? extends U> keyExtractor) {
return (ComparatorPlus & Serializable) comparing(keyExtractor).reversed();
}
public static ComparatorPlus moveForward(
Predicate super T> predicate) {
return moveBack(predicate.negate());
}
public static ComparatorPlus moveForward(
Predicate super T> predicate,
Comparator super T> sub) {
return (ComparatorPlus & Serializable) (c1, c2) ->
predicate.test(c1) && predicate.test(c2) ? sub.compare(c1, c2)
: moveForward(predicate).compare(c1, c2);
}
public static ComparatorPlus moveForward(
Predicate super T> predicate,
Comparator super T> sub1,
Comparator super T> sub2
) {
return (ComparatorPlus & Serializable) (c1, c2) ->
!predicate.test(c1) && !predicate.test(c2) ? sub2.compare(c1, c2)
: moveForward(predicate, sub1).compare(c1, c2);
}
public static ComparatorPlus moveBack(
Predicate super T> predicate) {
return (ComparatorPlus & Serializable) (c1, c2) ->
Boolean.compare(predicate.test(c1), predicate.test(c2));
}
public static ComparatorPlus moveBack(
Predicate super T> predicate,
Comparator super T> sub) {
return (ComparatorPlus & Serializable) (c1, c2) ->
predicate.test(c1) && predicate.test(c2) ? sub.compare(c1, c2)
: moveBack(predicate).compare(c1, c2);
}
public static ComparatorPlus moveBack(
Predicate super T> predicate,
Comparator super T> sub1,
Comparator super T> sub2) {
return (ComparatorPlus & Serializable) (c1, c2) ->
!predicate.test(c1) && !predicate.test(c2) ? sub2.compare(c1, c2)
: moveBack(predicate, sub1).compare(c1, c2);
}
default ComparatorPlus thenComparing(Comparator super T> other) {
Objects.requireNonNull(other);
return (ComparatorPlus & Serializable) (c1, c2) -> {
int res = compare(c1, c2);
return (res != 0) ? res : other.compare(c1, c2);
};
}
default > ComparatorPlus thenComparing(
Function super T, ? extends U> keyExtractor) {
return thenComparing(comparing(keyExtractor));
}
default ComparatorPlus thenReversedComparing(Comparator super T> other) {
return thenComparing(other.reversed());
}
default > ComparatorPlus thenReversedComparing(
Function super T, ? extends U> keyExtractor) {
return thenReversedComparing(comparing(keyExtractor));
}
default ComparatorPlus thenMoveForward(Predicate super T> predicate) {
return thenComparing(moveForward(predicate));
}
default ComparatorPlus thenMoveForward(
Predicate super T> predicate,
Comparator super T> sub) {
return thenComparing(moveForward(predicate, sub));
}
default ComparatorPlus thenMoveForward(
Predicate super T> predicate,
Comparator super T> sub1,
Comparator super T> sub2) {
return thenComparing(moveForward(predicate, sub1, sub2));
}
default ComparatorPlus thenMoveBack(Predicate super T> predicate) {
return thenComparing(moveBack(predicate));
}
default ComparatorPlus thenMoveBack(
Predicate super T> predicate,
Comparator super T> sub) {
return thenComparing(moveBack(predicate, sub));
}
default ComparatorPlus thenMoveBack(
Predicate super T> predicate,
Comparator super T> sub1,
Comparator super T> sub2) {
return thenComparing(moveBack(predicate, sub1, sub2));
}
// flip!!
default ComparatorPlus reversed() {
return (ComparatorPlus & Serializable) (c1, c2) -> this.compare(c2, c1);
}
}
函数式范式表达力真的强!!
( PS: 现在没学个Scala/Clojure好意思说自己会java ;) !! )