Java 8过滤器按每个id的最高值列出

时间:2018-06-05 13:24:28

标签: java lambda java-8 java-stream

有没有办法使用java 8功能和lambdas执行以下操作?

我有这个班级

public class A{
    private String id;
    private int version;
    // getters...
}

输入(列表按ID和升序排序):

[{"1",1},{"1",2},{"2",1},{"2",2}]

我希望列表中包含每个id的最高版本,因此结果应如下所示:

[{"1",2},{"2",2}]

我已经有了解决方案,但我不喜欢它。我想也许有一个更好的方法用java 8。

static List<A> removeOldVersions(List<A> aList) {
    Map<String, A> map = new HashMap<>();
    aList.forEach(a -> map.put(a.getId(), a));
    return (List<A>) map.values();
}

3 个答案:

答案 0 :(得分:3)

好吧,你可以收集到Map并通过BinaryOperator.maxBy合并条目。计算完成后,在其上调用values(将返回Collection<A>):

  yourList.stream()
        .collect(Collectors.toMap(
              A::getId,
              Function.identity(),
              BinaryOperator.maxBy(Comparator.comparing(A::getVersion))))
        .values()

答案 1 :(得分:1)

简介

这有两种方法,它们都使用Comparators,我建议您在以下链接中阅读更多相关内容:

https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html

我想向您展示我最简单的方法,而无需编写自己的过滤器/独特的alghorytm。此解决方案将使用Java 8的Stream API。

(假设您在两个示例中都使用了ArrayListHashSet。)

使用Streams

public class Sorter {

    private final class A {
        private String id;
        private int version;

        private A(String id, int version) {
            this.id = id;
            this.version = version;
        }

        public String getId() {
            return id;
        }

        public int getVersion() {
            return version;
        }
    }

    public void sort() {
        final ArrayList<A> list = new ArrayList<A>() {{
            add(new A("1", 1));
            add(new A("1", 2));
            add(new A("2", 1));
            add(new A("2", 2));
        }};

        //Using HashSet so we cannot have any duplicates.
        list.stream().sorted(Comparator.comparingInt(o -> o.version)).filter(distinctByKey(a -> a.id)).collect(Collectors.toSet());
    }

    private 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;
    }

}

希望这已经回答了你的问题。

答案 2 :(得分:0)

将每一对添加到Map,检查它是否已存在并且在覆盖之前具有较低的值。

经典方法:

{
    List<A> in = Arrays.asList(new A("'1'", 1),
                               new A("'1'", 2),
                               new A("'2'", 1),
                               new A("'2'", 2));

    Map<String, Integer> map = new LinkedHashMap<>(in.size()); // 'Linked' just keeps the original ordering
    for (A element : in) {
        @Nullable Integer version = map.get(element.id);
        if (version == null || version < element.version)
            map.put(element.id, element.version);
    }

    System.out.println(map);
}

输出:

{'1'=2, '2'=2}