我有一个对象列表,如下
public class Price{
private long id;
private String productid;
private long sequence;
private BigDecimal price;
}
我将有如下的对象列表
Price1 -> {1, "p1", 1, 1.0}
Price2 -> {2, "p1", 2, 2.0}
Price3 -> {3, "p1", 3, 3.0}
Price4 -> {4, "p2", 1, 1.0}
每个产品id可以有多个价格条目(按顺序排序)。最新的价格随最新的顺序而来。在上述数据中,产品p1的价格为3,产品p2的价格为1。
我需要过滤上面的java对象列表,只得到2个条目(id 3和4)。输出应该包含以下列表
Price3 -> {3, "p1", 3, 3.0}
Price4 -> {4, "p2", 1, 1.0}
对Java8流有什么帮助吗?
使用Collectors.groupingBy
对每个产品的价格进行分组,然后使用Collectors.maxBy
从列表中获取最新价格。结果是每个产品最新价格的地图。
Map<String, Price> lastPricePerProduct = data.stream().collect(
Collectors.groupingBy(Price::getProductid, Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparing(Price::getSequence)), Optional::get));
Collectors.toMap
和BinaryOperator.maxBy
更优雅的解:
Map<String, Price> lastPricePerProduct = data.stream().collect(
Collectors.toMap(Price::getProductid,Function.identity(),
BinaryOperator.maxBy(Comparator.comparing(Price::getSequence))));
这里您需要使用groupingBy
而不是filter
来获得所需的输出。请参考下面的例子:
public class Main {
public static void main(String[] args) {
List<Price> data = Arrays.asList(
new Price(1, "p1", 1, new BigDecimal(1.0)),
new Price(2, "p1", 2, new BigDecimal(2.0)),
new Price(3, "p1", 3, new BigDecimal(3.0)),
new Price(4, "p2", 1, new BigDecimal(1.0)));
Map<String, Object> result = data.stream().collect(Collectors.groupingBy(Price::getProductid,
Collectors.collectingAndThen(
Collectors.reducing((Price p1, Price p2) -> p1.getSequence() > p2.getSequence() ? p1 : p2),
Optional::get)));
System.out.println(result.values());
}
}
输出:
[Price(id=3, productid=p1, sequence=3, price=3), Price(id=4, productid=p2, sequence=1, price=1)]
Price
class:
@AllArgsConstructor
@Data
public class Price {
private long id;
private String productid;
private long sequence;
private BigDecimal price;
}
你可以这样做:
prices.stream().collect(Collectors.groupingBy(Price::getProductid)).entrySet().forEach(e -> e.getValue().stream().max(Comparator.comparing(Price::getSequence)).get());
注意:我没有测试上面的代码,所以它可能有一些不正确的语义。
解释:
- 根据产品在地图中收集各自的价格对象。
Collectors.groupingBy(Price::getProductid)
- 浏览每个键的价格列表。
entrySet().forEach()
- 查找每个键和返回对象的最大序列。
max(Comparator.comparing(Price::getSequence)).get()
如果您需要进一步的帮助,请告诉我。
作为java.util.stream。Stream#predicate接受"无干扰、无状态的谓词",
我认为你应该使用Collection
。
我会使用java.util.stream。
java.util.stream. Stream . # collection .Collector
。
你可以试试:
List<Price> list = new ArrayList<>();
Price p1 = new Price(1,"p1",1,new BigDecimal(1.0));
Price p2 = new Price(2,"p1",2,new BigDecimal(2.0));
Price p3 = new Price(3,"p1",3,new BigDecimal(3.0));
Price p4 = new Price(4,"p3",1,new BigDecimal(1.0));
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
List<Price> priceList = list.stream().sorted(Comparator.comparing(Price::getSequence).reversed())
.filter(distinctByKey(Price::getProductid))
.collect(Collectors.toList());
System.out.print(priceList);
public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor)
{
Map<Object, Boolean> map = new ConcurrentHashMap<>();
return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
输出:[Price{id=3, productid='p1', sequence=3, price=3}, Price{id=4, productid='p3', sequence=1, price=1}]