Java8流中的条件排序
我试图根据买入或卖出方向对股票订单列表进行排序 我试过这样的方法:Java8流中的条件排序,java,sorting,generics,lambda,java-stream,Java,Sorting,Generics,Lambda,Java Stream,我试图根据买入或卖出方向对股票订单列表进行排序 我试过这样的方法: orders.stream() .sorted(o -> "BUY".equals(o.side) ? comparing(Order::getPrice) : comparing(Order::getPrice).reversed()); 我看到下面的错误信息,我不清楚 不兼容的类型。必需的int,但已向Comparator推断
orders.stream()
.sorted(o -> "BUY".equals(o.side) ?
comparing(Order::getPrice) :
comparing(Order::getPrice).reversed());
我看到下面的错误信息,我不清楚
不兼容的类型。必需的int,但已向Comparator推断“comparing”:不存在类型变量T,U的实例,因此Comparator符合Integer
我有另一个想法:如何根据类型对流进行分区,然后在后期修复排序顺序
Map<Boolean, List<Order>> filtered = orders.stream()
.sorted(Order::getPrice)
.collect(Collectors.partitioningBy(o -> "BUY".equals(o.side)));
// #partitioningBy guarantees true/false will be in the map
List<Order> bought = filtered.get(true);
List<Order> sold = filtered.get(false);
Collections.reverse(sold); //since you want sold backwards
Map filtered=orders.stream()
.sorted(订单::getPrice)
.collect(collector.partitionby(o->“BUY.”等于(o.side));
//#Partitioning By保证真/假将出现在地图上
List bunded=filtered.get(true);
列表已售出=已筛选。获取(false);
收款。反向(已售出)//既然你想倒卖
缺点是对于大订单(成百上千的商品),这可能会很慢,因为您同时进行买卖(而不是两个较小的种类)。您可以将排序移到下游收集器(甚至是收集的对象)中,但它需要更多的代码:
Map<Boolean, List<Order>> filtered = orders.stream()
.collect(Collectors.partitioningBy(o -> "BUY".equals(o.side)));
List<Order> bought = filtered.get(true);
List<Order> sold = filtered.get(false);
bought.sort(Comparator.comparingInt(Order::getPrice));
sold.sort(Comparator.comparingInt(Order::getPrice).reversed());
Map filtered=orders.stream()
.collect(collector.partitionby(o->“BUY.”等于(o.side));
List bunded=filtered.get(true);
列表已售出=已筛选。获取(false);
bunded.sort(Comparator.comparingit(Order::getPrice));
sell.sort(Comparator.comparingit(Order::getPrice.reversed());
对于较小的输入,第一个是可以接受的。最重要的是,它消除了(有些)混乱的lambda,消除了三元/lambda混合
编辑:
如果您只对其中一个结果感兴趣,那么不需要将逻辑放在同一个流中:
//To fetch the items that were not "BUY"
List<Order> sold = orders.stream()
.filter(o -> !"BUY".equals(o.side))
.sorted(Comparator.comparingInt(Order::getPrice).reversed())
.collect(Collectors.toList());
//or if you're looking for the sold items at this point in code
List<Order> bought = orders.stream()
.filter(o -> "BUY".equals(o.side))
.sorted(Comparator.comparingInt(Order::getPrice))
.collect(Collectors.toList());
//获取不是“购买”的项目
List Seld=orders.stream()
.过滤器(o->!“购买”。等于(o侧))
.sorted(Comparator.comparingInt(Order::getPrice).reversed())
.collect(Collectors.toList());
//或者,如果您正在代码中查找此时已售出的项目
List bunded=orders.stream()
.filter(o->“购买”。等于(o.side))
.sorted(Comparator.comparingInt(Order::getPrice))
.collect(Collectors.toList());
我有另一个想法:如何根据类型对流进行分区,然后对排序顺序进行后期修复
Map<Boolean, List<Order>> filtered = orders.stream()
.sorted(Order::getPrice)
.collect(Collectors.partitioningBy(o -> "BUY".equals(o.side)));
// #partitioningBy guarantees true/false will be in the map
List<Order> bought = filtered.get(true);
List<Order> sold = filtered.get(false);
Collections.reverse(sold); //since you want sold backwards
Map filtered=orders.stream()
.sorted(订单::getPrice)
.collect(collector.partitionby(o->“BUY.”等于(o.side));
//#Partitioning By保证真/假将出现在地图上
List bunded=filtered.get(true);
列表已售出=已筛选。获取(false);
收款。反向(已售出)//既然你想倒卖
缺点是对于大订单(成百上千的商品),这可能会很慢,因为您同时进行买卖(而不是两个较小的种类)。您可以将排序移到下游收集器(甚至是收集的对象)中,但它需要更多的代码:
Map<Boolean, List<Order>> filtered = orders.stream()
.collect(Collectors.partitioningBy(o -> "BUY".equals(o.side)));
List<Order> bought = filtered.get(true);
List<Order> sold = filtered.get(false);
bought.sort(Comparator.comparingInt(Order::getPrice));
sold.sort(Comparator.comparingInt(Order::getPrice).reversed());
Map filtered=orders.stream()
.collect(collector.partitionby(o->“BUY.”等于(o.side));
List bunded=filtered.get(true);
列表已售出=已筛选。获取(false);
bunded.sort(Comparator.comparingit(Order::getPrice));
sell.sort(Comparator.comparingit(Order::getPrice.reversed());
对于较小的输入,第一个是可以接受的。最重要的是,它消除了(有些)混乱的lambda,消除了三元/lambda混合
编辑:
如果您只对其中一个结果感兴趣,那么不需要将逻辑放在同一个流中:
//To fetch the items that were not "BUY"
List<Order> sold = orders.stream()
.filter(o -> !"BUY".equals(o.side))
.sorted(Comparator.comparingInt(Order::getPrice).reversed())
.collect(Collectors.toList());
//or if you're looking for the sold items at this point in code
List<Order> bought = orders.stream()
.filter(o -> "BUY".equals(o.side))
.sorted(Comparator.comparingInt(Order::getPrice))
.collect(Collectors.toList());
//获取不是“购买”的项目
List Seld=orders.stream()
.过滤器(o->!“购买”。等于(o侧))
.sorted(Comparator.comparingInt(Order::getPrice).reversed())
.collect(Collectors.toList());
//或者,如果您正在代码中查找此时已售出的项目
List bunded=orders.stream()
.filter(o->“购买”。等于(o.side))
.sorted(Comparator.comparingInt(Order::getPrice))
.collect(Collectors.toList());
您可能希望使用由o.side
参数调整的比较器
static Comparator<Order> buyComparator() {
return (l, r) -> {
Comparator<Order> comparator = Comparator.comparing(Order::getPrice);
comparator = "BUY".equals(l.side) && "BUY".equals(r.side) ?
comparator : comparator.reversed();
return comparator.compare(l ,r);
};
}
顺便说一下,代码中有两个错误:
没有Stream::sort
方法,但是
流本身没有终止,因此管道永远不会执行。这样的终端操作是收集
,减少
,查找第一个
等
…如果我只使用排序(比较(Order::getPrice))而不是三元操作,为什么它不抱怨呢
因为sorted
方法需要Comparator
,但是您的lambda表达式与此不兼容
首先,lambda表达式以o->…
开头,只要Comparator
中的方法是int compare(to1,t2)
就不正确,因此lambda表达式应该类似于(o1,o2)
其次,返回类型必须是int
(因为int比较(to1,t2)
)。仅使用比较(Order::getPrice)
是可以的,但只要选择lambda表达式而不是方法引用,那么返回类型就会清晰可见:
// this is your lambda expression
BiFunction<Order, Order, Comparator<Order>> biFunction = (l, r) ->
"BUY".equals(l.side) && "BUY".equals(r.side) ?
Comparator.comparing(Order::getPrice) :
Comparator.comparing(Order::getPrice).reversed();
List<Order> sortedOrders = orders.stream()
.sorted((l, r) -> biFunction.apply(l, r).compare(l ,r))
.collect(Collectors.toList());
//这是lambda表达式
双功能双功能=(l,r)->
“买”等于(左面)和“买”等于(右面)?
Comparator.comparing(订单::getPrice):
Comparator.comparing(Order::getPrice).reversed();
List sortedOrders=orders.stream()
.sorted((l,r)->biFunction.apply(l,r).compare(l,r))
.collect(Collectors.toList());
这显然不是比较器,但可以使用。整个过程可以简化为我上面描述的解决方案。您可能需要使用这个比较器,通过o.side
参数进行调整
static Comparator<Order> buyComparator() {
return (l, r) -> {
Comparator<Order> comparator = Comparator.comparing(Order::getPrice);
comparator = "BUY".equals(l.side) && "BUY".equals(r.side) ?
comparator : comparator.reversed();
return comparator.compare(l ,r);
};
}
BUY 3
BUY 4
SELL 9
BUY 5
SELL 6
BUY 7
SELL 2
SELL 1
BUY 8
// We define a comparator here which returns ascending order if the side is BUY,
// or descending if it is SELL.
final Comparator<Order> comparator = (left, right) -> {
Comparator<Order> c = Comparator.comparing(Order::getPrice);
if (Objects.equals(left.getSide(), "SELL")) {
c = c.reversed();
}
return c.compare(left, right);
};
// We stream over the orders, and partition them by their side. We sort the
// resulting lists by their own comparison method.
Map<String, List<Order>> map = orders.stream()
.collect(Collectors.groupingBy(Order::getSide, toSortedList(comparator)));
Iterator<Order> buyIt = map.get("BUY").iterator();
Iterator<Order> sellIt = map.get("SELL").iterator();
// At last, we stream again over the elements, consuming from both iterators
// based on the value of 'side'
orders.stream()
.map(order -> Objects.equals(order.getSide(), "BUY") ? buyIt.next() : sellIt.next())
.forEach(System.out::println);
// Almost the same as Collectors.toList(), but sorts the list by the provided
// comparator.
public static <T> Collector<T, List<T>, List<T>> toSortedList(Comparator<T> comparator) {
return Collector.of(
ArrayList::new,
List::add,
(left, right) -> {
left.addAll(right); return left;
},
list -> list.stream()
.sorted(comparator)
.collect(Collectors.toList())
);
}