我正在尝试根据买入或卖出方向对股票订单列表进行排序。
我试过这样的方法:
orders.stream()
.sorted(o -> "BUY".equals(o.side) ?
comparing(Order::getPrice) :
comparing(Order::getPrice).reversed());
我看到下面的错误消息,我不清楚。
不兼容的类型。必需的int,但已将“comparing”推断给Comparator:不存在类型变量T,U的实例,因此Comparator符合Integer。
这里有一些东西可以根据属性对列表进行排序以比较规则,同时仍然保持该属性的原始顺序。
假设我们有一个order
:
class Order {
private String side;
private int price;
// Getters and setters omitted for brevity
}
还假设我们有一个订单列表:
BUY 4
BUY 5
SELL 1
BUY 8
SELL 6
BUY 3
SELL 9
SELL 2
BUY 7
以下代码将按升序排列购买订单,降序排列销售订单,但保留原始列表中的购买和销售顺序。在本例中,第一个条目是购买订单,第二个也是购买订单,第三个是销售订单,等等。结果是:
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())
);
}
我有另一个想法:如何根据类型对流进行分区,然后对排序顺序进行后期修复?
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<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());
对于较小的输入,可以接受第一个输入。最重要的是,它消除了(有些)凌乱的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());
您可能需要使用这个比较器
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);
};
}
这样,用法就相当简单了,您可以通过流API返回一个新的排序列表,或对原始列表进行修改:
List<Order> sortedOrders = orders.stream()
.sorted(buyComparator())
.collect(Collectors.toList());
Collections.sort(orders, buyComparator());
顺便说一下,您的代码中有两个错误:
收集
、减少
、findFirst
等......如果我只使用排序(比较(Order::getPrice))而不是三元操作,为什么它不抱怨呢?
因为排序的方法需要比较器
首先,lambda表达式以o开头-
其次,返回类型必须是int
(因为int比较(T o1, T o2)
)。仅使用比较(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());
这显然不是比较器
哦,那些狡猾的Java8条带有lambdas的溪流。它们非常强大,但是复杂的东西需要一点时间来包裹它。 假设我有一个类型,其属性为。假设我有这些用户的地图 ?
问题内容: 我有3个字段的“任务”表: 日期 优先级(0,1,2) 完成(0,1) 我想要实现的是对整个表按“完成”标志排序,未完成的任务应按优先级排序,而已完成的任务应按日期排序: 从按完成的asc的任务顺序中选择* 如果完成= 0,则按优先级依次排序 如果完成= 1,则另外按日期顺序排序 不使用工会就可以在MySQL中做到这一点吗? 谢谢。 问题答案: 您可以尝试在使用aux来计算aux时根据
我想显示一个名为listaBaresFiltrada的列表,按多个值排序。 Evento模型: 现在,我可以创建第一个排序条件,如下所示: 但我不知道如何包括其他两个排序条件。
我有一个的列表 其中是一个模型类,如下所示 null
我有一个列表,像
寻找有关以下用例的建议或解决方案 应用程序接收按功能键(如员工id)标识的更改时间排序的消息。功能键可以有多条消息 每条消息都会触发一个工作流。如果员工有待定工作流,则希望将新消息排队,直到待定工作流完成 是否有任何方法可以在节奏中对消息重新排序,以将它们作为由消息中的功能键标识的组进行处理?