通过流过滤对象



我有一个对象列表,如下

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.toMapBinaryOperator.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)]

Priceclass:

@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());

注意:我没有测试上面的代码,所以它可能有一些不正确的语义。

解释:

  1. 根据产品在地图中收集各自的价格对象。Collectors.groupingBy(Price::getProductid)
  2. 浏览每个键的价格列表。entrySet().forEach()
  3. 查找每个键和返回对象的最大序列。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}]

最新更新