使用流映射列表中的嵌套对对象,按成对键分组

问题描述 投票:0回答:2

假设我有一个嵌套对象,其中包含一对不同的 String-Integer 对象(我们将每个这样的对称为

endpoint
)。有一个名为
pair
的列表,其中恰好包含 2 个
endpoint
对象。另一个名为
pairs
的列表可以包含任意数量(例如
n
pair
条目,我需要在新对象中收集每对唯一的字符串及其相应的整数值。

考虑现有对象的以下类:

public class Endpoint {
    private String key;
    private Integer number;

    public Endpoint(String key, Integer number) {
        this.key = key;
        this.number = number;
    }

    // Getters, Setters and toString()
}

public class Pair {
    // It will have exactly 2 entries
    List<Endpoint> pair;

    public Pair(List<Endpoint> pair) {
        this.pair = pair;
    }

    // Getters, Setters and toString()
}

考虑以下对象(转换前),其中

pairs
List<Pair>
pairs
中的条目可以按任意顺序排列:

pairs: [
    pair: [{"p1",1000},{"p2",2000}],
    pair: [{"p1",3000},{"p3",4000}],
    pair: [{"p2",5000},{"p3",6000}],
    pair: [{"p1",2000},{"p2",3000}],
    pair: [{"p1",2001},{"p2",3001}],
    pair: [{"p1",4000},{"p3",5000}],
    pair: [{"p1",4001},{"p3",5001}],
    pair: [{"p2",6000},{"p3",7000}],
    pair: [{"p2",6001},{"p3",7001}]
]

考虑使用以下类来填充结果:

public class CustomEndpoint {
    private String key;
    // `numbers` can have any number of entries
    private List<Integer> numbers;

    public CustomEndpoint(String key, List<Integer> numbers) {
        this.key = key;
        this.numbers = numbers;
    }

    // Getters, Setters and toString()
}

public class CustomPair {
    // It will have exactly 2 entries
    List<CustomEndpoint> pair;

    public CustomPair(List<CustomEndpoint> pair) {
        this.pair = pair;
    }

    // Getters, Setters and toString()
}

我需要按如下方式收集:

custom-pairs: [
    custom-pair: {[{"p1", [1000,2000,2001]}, {"p2", [2000,3000,3001]}]},
    custom-pair: {[{"p1", [3000,4000,4001]}, {"p3", [4000,5000,5001]}]},
    custom-pair: {[{"p2", [5000,6000,6001]}, {"p3", [6000,7000,7001]}]}
]

其中

custom-pairs
List<CustomPair>
numbers
列表中的条目顺序必须保持与输入
pair
相同。例如,由于 p1 中的
1000
与 p2 中的
2000
配对,如果
1000
是 p1 的
numbers
列表中的第一个条目,那么
2000
也必须是 p2 的
numbers
列表中的第一个条目,对于p1 和 p2 配对在一起的组合。

如何使用 Java 中的流来做到这一点?

java list java-stream java-11
2个回答
1
投票

在您对课程及其结构进行澄清之后,我更新了我的答案。

基本上,您可以通过两个包含端点的键对列表

Pair
中的
pairs
元素进行分组。为了使代码更具可读性,我在您的
Pair
类 (
getPairKeys
) 中添加了一个方法,该方法返回链接在一起的两个端点的键,但如果您愿意,您可以通过简单地在流中链接键来避免这种情况.

按键对

Pair
元素进行分组后,您将得到一个
Map
,其中每个链式键映射到具有相同键的 n 个
Pair
实例。此时,您可以流式传输
Map
条目,将每个条目映射到
CustomPair
,按第一个
CustomEndpoint
的第一个数字对它们进行排序,并最终收集实例。

为了使我的解决方案发挥作用,我假设

equals
(以及
hashCode
)的实现存在于
Pair
Endpoint
中。另外,正如我之前所说,我在
getPairKeys
类中添加了
Pair
方法来获取映射每个
String
Pair
,并在
getFirstPairInitialNumber
类中添加了
CustomPair
方法来建立排序顺序其中
CustomPair
。我刚才提到的所有代码都可以在下面的链接中查阅。我不想将其发布在这里,以避免文字墙并只关注实际的解决方案。

List<CustomPair> listRes = pairs.stream()
        .collect(Collectors.groupingBy(Pair::getPairKeys))  //Grouping the Pairs by the keys of the two EndPoints (key1:key2)
        .entrySet().stream()    //Streaming the entries of the map
        .map(entry -> {
            String key1 = null, key2 = null;

            //Lists for the values of the CustomEndpoint
            List<Integer> listValues1 = new ArrayList<>();
            List<Integer> listValues2 = new ArrayList<>();

            //Retrieving the keys and adding each pair's number to the respective lists
            for (Pair p : entry.getValue()) {
                key1 = p.getPair().get(0).getKey();
                key2 = p.getPair().get(1).getKey();

                listValues1.add(p.getPair().get(0).getNumber());
                listValues2.add(p.getPair().get(1).getNumber());
            }

            //Returning the new CustomPair in place of the two grouped by Pair
            return new CustomPair(new ArrayList<>(List.of(
                    new CustomEndpoint(key1, listValues1),
                    new CustomEndpoint(key2, listValues2))));
        })
        .sorted(Comparator.comparing(CustomPair::getFirstPairInitialNumber))    //Ordering the CustomPair by the beginning of their endpoint range
        .collect(Collectors.toList());  //Collecting the CustomPair

这是测试代码的更新链接

https://ideone.com/G3XlRS

输出

enter image description here


0
投票
Map<List<String>, List<Pair>> groupedPairs = pairs.stream()
        .collect(Collectors.groupingBy(p -> List.of(
                p.getPair().getFirst().getKey(), 
                p.getPair().getLast().getKey())));
List<CustomPair> customPairs = groupedPairs.entrySet().stream()
        .map(e -> new CustomPair(List.of(
                new CustomEndpoint(
                        e.getKey().getFirst(),
                        e.getValue().stream()
                                .map(p -> p.getPair().getFirst().getNumber())
                                .toList()),
                new CustomEndpoint(
                        e.getKey().getLast(),
                        e.getValue().stream()
                                .map(p -> p.getPair().getLast().getNumber())
                                .toList()))))
        .toList();

首先按键将

Pair
对象分组为
Map<List<String>, List<Pair>>
,其中键是包含
List<String>
的键的 2 元素
Pair
,值是包含这两个元素的所有对的列表键。 然后将
Map
中的每个条目映射到
CustomPair

© www.soinside.com 2019 - 2024. All rights reserved.