基于不同谓词和第二个谓词的过滤器列表

时间:2019-06-15 10:21:14

标签: java data-structures java-stream

我的对象看起来像下面的

Store {
   String shopId;
   long distance;
}

我有商店的清单。

List<Store> storesList = Arrays.asList(
    new Store (1, 1),
    new Store (1, 5),
    new Store (2, 2),
    new Store (1, 1), // this is duplicate
    new Store (1, 2),
    new Store (1, 1), // this is duplicate
    new Store (3, 7)
    new Store (3, 5)
);

输出

Store {shopId=1, distance=1}  // its fine to have any one among 3 duplicates
Store {shopId=2, distance=2}
Store {shopId=3, distance=5}

我可以像下面的

一样调用自己的distint方法
private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Map<Object, Boolean> seen = new ConcurrentHashMap<>();
    return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}

并像这样过滤它

List<Store> stores= storesList .stream()
        .filter(distinctByKey(pr -> Arrays.asList(pr.getShopId())))
        .collect(toList());

但是如何同时以较小的距离对它进行过滤?

3 个答案:

答案 0 :(得分:4)

 storesList.stream()
           .collect(Collectors.toMap(
                Store::getShopId,
                Function.identity(),
                BinaryOperator.minBy(Comparator.comparingLong(Store::getDistance))
              ))
           .values()
           .forEach(System.out::println);

您可以合并这些相同的Store(通过storeId),您会说,合并时,您将在两个商店之间使用最小的distance

答案 1 :(得分:2)

如果按过滤器之前的距离对流进行排序,则得到的距离最小:

List<Store> stores = storesList.stream()
        .sorted(Comparator.comparing(Store::getDistance))
        .filter(distinctByKey(it -> it.shopId))
        .collect(toList());

答案 2 :(得分:0)

您可以尝试以下方法:

Collection<Store> stores = storesList.stream()
        .collect(Collectors.groupingBy(Store::getShopId, 
                Collectors.collectingAndThen(
                        Collectors.minBy(Comparator.comparingLong(Store::getDistance)), 
                        Optional::get)))
        .values();

在开始时,您将按shopId进行分组,然后您使用的值为最小值distance。在Ende,您只是使用此地图的值作为结果。

如果您需要列表而不是收藏夹,则可以使用

new ArrayList<>(stores);