如何使用Java lambda来收集新类型列表中的元素?

Cug*_*uga 6 java lambda java-8 java-stream collectors

我一直在努力阅读javadocs,以确定如何使用lambdas优雅地将一种类型的行列表组合成另一种类型的分组列表.

我已经弄清楚如何使用Collectors.groupingBy语法来获取数据,Map<String, List<String>>但是因为结果将用于各种后来的函数调用...我理想地希望将这些缩减为包含以下内容的对象列表新的映射.

这是我的数据类型,RowData是源...我想将数据合并到一个列表中CodesToBrands:

class RowData {
    private String id;
    private String name;

    public RowData() {

    }

    public RowData(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class CodeToBrands {
    private String code;
    private List<String> brands = new ArrayList<>();

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public List<String> getBrands() {
        return brands;
    }

    public void addBrands(List<String> brands) {
        this.brands.addAll(brands);
    }

    public void addBrand(String brand) {
        this.brands.add(brand);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我正在编写的测试,试图弄明白......

@Test
public void testMappingRows() {
    List<RowData> rows = new ArrayList<>();
    rows.add(new RowData("A", "Foo"));
    rows.add(new RowData("B", "Foo"));
    rows.add(new RowData("A", "Bar"));
    rows.add(new RowData("B", "Zoo"));
    rows.add(new RowData("C", "Elf"));

    // Groups a list of elements to a Map<String, List<String>>
    System.out.println("\nMapping the codes to a list of brands");
    Map<String, List<String>> result = rows.stream()
                    .collect(Collectors.groupingBy(RowData::getId, Collectors.mapping(RowData::getName, Collectors.toList())));

    // Show results are grouped nicely
    result.entrySet().forEach((entry) -> {
        System.out.println("Key: " + entry.getKey());
        entry.getValue().forEach((value) -> System.out.println("..Value: " + value));
    });

    /**Prints:
     * Mapping the codes to a list of brands
        Key: A
        ..Value: Foo
        ..Value: Bar
        Key: B
        ..Value: Foo
        ..Value: Zoo
        Key: C
        ..Value: Elf*/

    // How to get these as a List<CodeToBrand> objects where each CodeToBrand objects to avoid working with a Map<String, List<String>>?
    List<CodeToBrands> resultsAsNewType;
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以提供任何帮助,试图在一个更容易使用的数据类型中获得相同的整体结果?

提前致谢

Fed*_*ner 7

您可以使用Collectors.toMap以下命令一次完成:

Collection<CodeToBrands> values = rows.stream()
    .collect(Collectors.toMap(
        RowData::getId,
        rowData -> {
            CodeToBrands codeToBrands = new CodeToBrands();
            codeToBrands.setCode(rowData.getId());
            codeToBrands.addBrand(row.getName());
            return codeToBrands;
        },
        (left, right) -> {
            left.addBrands(right.getBrands());
            return left;
        }))
    .values();
Run Code Online (Sandbox Code Playgroud)

然后,如果您需要List而不是a Collection,只需执行以下操作:

List<CodeToBrands> result = new ArrayList<>(values);
Run Code Online (Sandbox Code Playgroud)

如果您在类中有特定的构造函数和合并方法,则可以简化上面的代码CodeToBrands:

public CodeToBrands(String code, String brand) {
    this.code = code;
    this.brands.add(brand);
}

public CodeToBrands merge(CodeToBrands another) {
    this.brands.addAll(another.getBrands());
    return this;
}
Run Code Online (Sandbox Code Playgroud)

然后,只需:

Collection<CodeToBrands> values = rows.stream()
    .collect(Collectors.toMap(
        RowData::getId,
        rowData -> new CodeToBrands(rowData.getId(), rowData.getName()),
        CodeToBrands::merge))
    .values();
Run Code Online (Sandbox Code Playgroud)