Java 8过滤器基于嵌套对象属性的pojos列表

时间:2017-02-20 20:34:08

标签: java lambda java-8 java-stream

我有一份Thingy pojos列表,这样:

public class Thingy {
    private DifferentThingy nestedThingy;
    public DifferentThingy getNestedThingy() {
        return this.nestedThingy;
    }
}

...

public class DifferentThingy {
    private String attr;
    public String getAttr() {
        return this.attr;
    }
}

我想过滤

List<Thingy>

基于

是唯一的
attr
Thingy的

DifferentThingy

这是我到目前为止所尝试的内容:

private List<Thingy> getUniqueBasedOnDifferentThingyAttr(List<Thingy> originalList) {
    List<Thingy> uniqueItems = new ArrayList<Thingy>();
    Set<String> encounteredNestedDiffThingyAttrs= new HashSet<String>();
    for (Thingy t: originalList) {
        String nestedDiffThingyAttr = t.getNestedThingy().getAttr();
        if(!encounteredNestedDiffThingyAttrs.contains(nestedDiffThingyAttr)) {
            encounteredNestedDiffThingyAttrs.add(nestedDiffThingyAttr);
            uniqueItems.add(t);
        }
    }
    return uniqueItems;
}

我想使用Java 8流和lambdas为两个getter最终检索用于确定唯一性的属性,但我不确定如何。当比较属性位于pojo的顶层时,我知道怎么做,但是当属性嵌套在另一个对象中时却不知道。

5 个答案:

答案 0 :(得分:4)

你可以这样做:

originalList.stream()
    .collect(Collectors.toMap(thing -> thing.getNestedThingy().getAttr(), p -> p, (p, q) -> p))
    .values();

不确定是否是最佳方式,我在Android上,所以不要在日常工作中使用流。

<强> UPD

如果某人无法编译,我的测试文件有full code

答案 1 :(得分:4)

如何使用javaslang

使其更明确
javaslang.collection.List.ofAll(thingies)
  .distinctBy(t -> t.getNestedThingy().getAttr());
  

Javaslang核心是Java 8+的功能库。它有助于减少代码量并提高稳健性。功能编程的第一步是开始思考不可变的值。 Javaslang提供了不可变的集合以及对这些值进行操作的必要函数和控制结构。结果很美,只是工作。

答案 2 :(得分:2)

我保留了一组独特的嵌套东西的属性...... 然后我尝试添加一个元素。 当集合“增长”时,意味着遇到了一个唯一的元素。 当设置大小未更改时,表示此Thingy具有已遇到属性的NestedThingy。 再加上一个简单的测试:

public class Thingies {

    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        final Set<Object> seen = Collections.synchronizedSet(new HashSet<>());
        return t -> seen.add(keyExtractor.apply(t));
    }

    private static List<Thingy> getUniqueBasedOnDifferentThingyAttr(List<Thingy> originalList) {
        return originalList.stream()
                .filter(distinctByKey(thingy -> thingy.getNestedThingy().getAttr()))
                .collect(toList());
    }

    public static void main(String[] args) {
        List<Thingy> originalList = new ArrayList<>();
        originalList.add(new Thingy(new DifferentThingy("first")));
        originalList.add(new Thingy(new DifferentThingy("first")));
        originalList.add(new Thingy(new DifferentThingy("second")));
        System.out.println(getUniqueBasedOnDifferentThingyAttr(originalList));
    }
}

输出:

[first, second]

帮助OP的原始答案(有点冗长且对并行流不利)包含这样的方法:

private static List<Thingy> getUniqueBasedOnDifferentThingyAttr(List<Thingy> originalList) {
    final Set<String> uniqueAttributes = new HashSet<>(originalList.size());
    return originalList.stream()
            .filter(thingy -> {
                int initialSize = uniqueAttributes.size();
                uniqueAttributes.add(thingy.getNestedThingy().getAttr());
                return initialSize != uniqueAttributes.size();
            }).collect(toList());
}

答案 3 :(得分:2)

您可以使用比较器达到子对象属性的TreeSet

private static List<Thingy> getUniqueBasedOnDifferentThingyAttr(List<Thingy> originalList) {

    Set<Thingy> uniqueSet = new TreeSet<Thingy>(Comparator.comparing(thingy -> thingy.getNestedThingy().getAttr()));

    return originalList.stream()
            .filter(uniqueSet::add)
            .collect(Collectors.toList());
}

uniqueSet::add会产生足够的唯一性过滤器,因为只有当项目不在集合中时才会返回true。

答案 4 :(得分:0)

使用StreamEx

StreamEx.of(originalList).distinct(e -> e.getNestedThingy().getAttr()).toList();

AbacusUtil

Stream.of(originalList).distinct(e -> e.getNestedThingy().getAttr()).toList();