java - 使用流将 Java 列表转换为映射,其中映射中的每个值共享相同的属性

标签 java java-stream

我正在尝试将列表转换为映射,以便对于列表元素的某些属性,映射的键是元素 ID,值是具有相同属性的元素的其他元素 ID。使用 for 循环这是相当简单的,但我正在尝试仅使用 Java 流来完成此操作。主要目标是可读性,而不是性能。

这是使用 for 循环时的样子 - 在此示例中,属性是 colorId:

class Apple {
    int _appleId; // different for each apple
    int _colorId; // same for some apples

    Apple(int appleId, int colorId) {
        _appleId = appleId;
        _colorId = colorId;
    }

    int getAppleId() { return _appleId; }
    int getColorId() { return _colorId; }
}

public static void main(String[] args) {
    Apple apple1 = new Apple(1, 7);
    Apple apple2 = new Apple(2, 7);
    Apple apple3 = new Apple(3, 7);
    Apple apple4 = new Apple(4, 8);
    Apple apple5 = new Apple(5, 8);
    Apple apple6 = new Apple(6, 9);

    List<Apple> apples = List.of(apple1, apple2, apple3, apple4,
        apple5, apple6);

    // applesByColor: {7=[1, 2, 3], 8=[4, 5], 9=[6]}
    Map<Integer, Set<Integer>> applesByColor = apples.stream().collect(
        Collectors.groupingBy(Apple::getColorId,
            Collectors.mapping(Apple::getAppleId, Collectors.toSet())));

    // applesWithSameColor:
    // {1=[1, 2, 3], 2=[1, 2, 3], 3=[1, 2, 3], 4=[4, 5], 5=[4, 5], 6=[6]}
    Map<Integer, Set<Integer>> applesWithSameColor = new HashMap<>();
    for (var entry : applesByColor.entrySet()) {
        for (var appleId : entry.getValue()) {
            applesWithSameColor
                .computeIfAbsent(appleId, k -> new HashSet<>())
                .addAll(entry.getValue());
        }
    }
}

这是我对 applesWithSameColor 的理想结果:

best:   {1=[2, 3], 2=[1, 3], 3=[1, 2], 4=[5], 5=[4]}
better: {1=[2, 3], 2=[1, 3], 3=[1, 2], 4=[5], 5=[4], 6=[]}
good:   {1=[1, 2, 3], 2=[1, 2, 3], 3=[1, 2, 3], 4=[4, 5], 5=[4, 5], 6=[6]}

该示例显示了良好输出。

使用 Java 流执行此操作的好方法是什么?如果我们也能避免创建中间映射 applesByColor 那就太理想了。

最佳答案

您可以仅从 applesByColor Map 流式传输值,然后为 Set 中的每个值创建条目,然后将它们收集到 Map

Map<Integer, Set<Integer>> applesWithSameColor = applesByColor.values().stream()
            .flatMap(set -> set.stream().map(val -> Map.entry(val, set)))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

如果出现重复的键,您还可以使用合并功能,以避免冲突

collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) ->v1)));

关于java - 使用流将 Java 列表转换为映射,其中映射中的每个值共享相同的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59470959/

相关文章:

java - 当 JInternalFrame 在 JFrame/JDesktopPane 中可见时,如何禁用/启用 JFrame 组件?

java - 一些线程卡在 semaphore.aquire() (threads/semaphore/countdownlatch)

c# - 用于声卡信号分析的 Java 或 C# 库

java - JTable 未从 .text 文件填充

java - 无法使用 Thymeleaf/Spring-Boot 迭代 List<List<String>>

Java Streams 检查空值

java - 如何使用流 api 将单独的单词字符串转换为单独的列表元素

java - 在 Java 8 计算其值后返回映射键的方法

Java流: How to find id from json?

Java流删除前三个元素