当前位置: 首页 > 知识库问答 >
问题:

如何用Java 8 Stream展平列表的嵌套映射?[重复]

甘英光
2023-03-14

我有一个这样的结构:

public class Category {
    private String tag;
    private String name;
    private String description;
    private List<Item> items;
}

项目看起来像这样

public class Item {
    private String itemTag;
    private String itemName;
    private String itemType;
    private Integer itemStatus;
    private List<Item> items;
}

这不是最好的设计-我知道,但我没有能力改变这个设计。

我正在尝试找到一种方法,将此结构扁平化为单个Stream,并找到一个itemTag

String tagToFind = "someTag";
List<Category> categories = getCategoriesList(); // <-- returns a list of Category
Item item = categories.stream()
                .flatMap(category -> category.getItems().stream())
                .filter(tagToFind.equals(item.getItemTag()))
                .findFirst();

但这仅搜索项目列表的一个级别。如果我想更深入,我可以简单地做:

Item item = categories.stream()
                .flatMap(category -> category.getItems().stream())
                .flatMap(item->item.getItems().stream()))
                .filter(tagToFind.equals(item.getItemTag()))
                .findFirst();

这很好。但我正试图找到一种更具可扩展性的方法来实现这一点,它可以像嵌套列表一样深入。有没有有效的方法来做到这一点?

共有2个答案

寿丰
2023-03-14

另一种方式:

public Item getFirstItemWithTag(List<Category> categories, String tag) {

        List<List<Item>> items = categories
                .stream()
                .map(Category::getItems)
                .collect(Collectors.toList());

        for(List<Item> items1 : items) {
            List<Item> itemsToAdd = items1.stream().filter(Objects::nonNull).collect(Collectors.toList());

            Optional<Item> first = itemsToAdd
                    .stream()
                    .filter(item -> item != null && tag.equals(item.getItemTag()))
                    .findFirst();

            if (first.isPresent()) {
                return first.get();
            }

            do {

                Stream<Item> itemStream = itemsToAdd
                        .stream()
                        .map(Item::getItems)
                        .flatMap(Collection::stream)
                        .filter(Objects::nonNull);

                first = itemsToAdd
                        .stream()
                        .filter(item -> item != null && tag.equals(item.getItemTag()))
                        .findFirst();

                if (first.isPresent()) {
                    return first.get();
                }

                itemsToAdd = itemStream
                        .collect(Collectors.toList());
            } while (!itemsToAdd.isEmpty());
        }


        return null;
    }

这也移除了< code>Item的空条目,并且比在过滤之前收集< code>Item的完整列表更快,因为它在发现时进行过滤。

权承
2023-03-14

您需要一个单独的递归方法。你可以这样做:

Optional<Item> item = categories.stream()
        .flatMap(category -> category.getItems().stream())
        .flatMap(MyClass::flatMapRecursive)
        .filter(i -> tagToFind.equals(i.getItemTag()))
        .findFirst();

使用此flatMapRecursive()方法:

public Stream<Item> flatMapRecursive(Item item) {
    return Stream.concat(Stream.of(item), item.getItems().stream()
            .flatMap(MyClass::flatMapRecursive));
}

还有一点需要考虑:< code>flatMapRecursive()方法不做空检查,所以每一项至少需要一个空列表,否则会得到一个< code > NullPointerException 。

如果null值是可能的,则可以使用 :

public Stream<Item> flatMapRecursive(Item item) {
    return Stream.concat(Stream.of(item), Optional.ofNullable(item.getItems())
            .orElseGet(Collections::emptyList)
            .stream()
            .flatMap(MyClass::flatMapRecursive));
}

或者在使用之前对< code >项目进行空检查:

public Stream<Item> flatMapRecursive(Item item) {
    if (item.getItems() == null) {
        return Stream.empty();
    }
    return Stream.concat(Stream.of(item), item.getItems().stream()
            .flatMap(MyClass::flatMapRecursive));
}
 类似资料:
  • 我如何在下面的场景中使用Mapstruct进行bean映射。 现在我想把sourceId映射到targetId,courseName映射到subjectName,studentName映射到memberName(list到list)。

  • 我正在尝试映射我的遗留API对象(我无法更改它),该对象具有嵌套的原始类型属性。列表的元素与DTO列表的元素不兼容,应显式映射为嵌套。不幸的是,MapStruct似乎认为原始与所有类型化列表兼容,并忽略了我试图指定的任何映射,而生成的代码不能正常工作,随后在序列化程序的某个地方产生错误。 我的API对象具有嵌套的原始类型列表: 我的DTO对象具有DTO值类型元素的泛型类型列表: ...但MapSt

  • 问题内容: 给定一个,其中值是a 或另一个,那么如何使用Java 8将地图展平到单个值列表? 例: 对于上面的示例,我想要以下列表: 我知道可以这样做: 我该如何使用? 编辑: 经过一番游戏后,我发现了: 问题答案: 您可以定义一个递归方法来展平一个地图并将其用作函数或直接调用它来使用。 例: 对于给定的嵌套地图,它会打印 [value1,value2,value3.1,value3.2,valu

  • 如何使用MapStruct映射嵌套列表? 下面是我的实体类: 我想把它映射到: 现在,我的映射器看起来像: 但它只映射“普通”属性,如Long、intger等,但它避免了嵌套列表。

  • 问题内容: 也许有人可以帮助我。我试图将以下ist放到pandas数据框中: 结果应如下所示: 但是我尝试做的所有事情都无法获得预期的结果。我用了这样的东西: 但是然后我松开了_source字段之外的类型。我也尝试与 但是我不知道如何使用字段_source并将其附加到原始数据帧。 有人知道如何做到这一点并达到预期的结果吗? 问题答案: 用途:

  • < code>[[{header=C,value=dsd},{header=D,value=test},{header=E,value=e},{header=F,value=hhh},{header=G,value=ghgh}]] 上面是JsonLists数组的数组,我需要将外部数组扁平化为JsonLists的内部数组。 我最终也只会从JsonList中获取值,并将这些值放入它自己的单独数组中: