使用流映射嵌套对象以配对列表中的所有可能组合

Mapping nested objects using streams to pair all possible combinations in a List

假设我有一个嵌套对象,其中包含一对不同的 String-Integer 对象(我们将每一对称为 endpoint)。有一个名为 pair 的列表,它恰好包含 2 个 endpoint 对象。另一个名为 pairs 的列表可以包含任意数量的(比如 npair 条目,我需要在新对象中收集每对唯一的字符串及其相应的整数值。

考虑以下 类 现有对象:

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

如何在 Java 中使用 Streams 执行此操作?

在您对 classes 及其结构进行说明后,我更新了我的答案。

基本上,您可以通过包含的两个端点的键对列表 pairs 中的 Pair 元素进行分组。为了使代码更具可读性,我在你的 Pair class (getPairKeys) 中添加了一个方法,其中 returns 两个端点的键链接在一起,但你可以避免它如果您愿意,只需将密钥直接链接到流中即可。

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

为了使我的解决方案有效,我假设 equals(以及 hashCode)的实现存在于 PairEndpoint 中.另外,正如我之前所说,我在你的 Pair class 中添加了一个 getPairKeys 方法来获得一个 String 映射每个 Pair 和一个 getFirstPairInitialNumber方法在CustomPairclass之间建立排序CustomPair。我刚才提到的所有代码都可以在下面的 link 中查阅。我宁愿不 post 在这里避免文字墙,只关注实际的解决方案。

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

这是更新后的 link 来测试代码

https://ideone.com/G3XlRS

输出