【问题标题】:Transforming Map<Key, List<Value>> to Map<Key, Value>将 Map<Key, List<Value>> 转换为 Map<Key, Value>
【发布时间】:2015-06-25 12:40:09
【问题描述】:

我有什么:

    SortedSet<Person> ss = new TreeSet<>();

    ss.add(new Person("John", "Doe", 20));
    ss.add(new Person("Max", "Power", 26));
    ss.add(new Person("Bort", "Bort", 30));
    ss.add(new Person("Scorpio", "McGreat", 56));

    Map<Integer, List<Person>> list = ss.stream().collect(Collectors.groupingBy(p -> p.name.length()));

我需要将 Map 转换为 Map&lt;Integer, Person&gt; 我知道我需要为此使用 flatMap 但我不知道如何。

到目前为止我所做的尝试:获取值集并对其进行平面映射。

Map <Integer, Person> list2 = list.values()
                                    .stream()
                                    .flatMap(f -> f.stream())
                                    .collect(Collectors.groupingBy(f -> f.name.length()); //doesn't work

问题:据我了解,当您通过流创建地图时,Java 会将值作为列表返回,我如何对这些列表进行平面映射?

附加信息: compareTo 的实现

@Override
public int compareTo(Person o) {

    int cmp = this.surname.compareTo(o.surname);
    if(cmp == 0){
        cmp = this.name.compareTo(o.name);
    }

    return cmp;
}

免责声明:

我知道用例有点奇怪,因为我根据长度进行排序,并通过比较名称的长度来使用 compareTo。恕我直言,这对这个问题无关紧要,因为我总是会得到一个Map&lt;Key, List&lt;Value&gt;&gt;。 问题是:我如何获得Map&lt;Key,Value&gt;

【问题讨论】:

  • 如果你有两个长度相同的名字怎么办?
  • 其实你的要求没有意义。您想按属性分组,这意味着它不一定是双射函数。因此,结果映射的值的类型默认为列表。如果您知道您应用的功能是双射的,您可以提供另一个下游收集器/或使用toMap 收集器,将抛出合并作为参数(最好的选择 IMO)。
  • 如果两个名字完全相等(根据 compareTo),那么 Person 将不会被添加到列表中,因为它是一个 Set,但恕我直言,这对于如何对列表进行平面映射的问题并不重要.
  • 你用来分组的属性是长度。所以你可以有两个不同的名字(因此在集合中)具有相同的长度......
  • 你能给出一个代码示例吗? p.s:即使该列表仅包含一个元素,我也总是得到一个列表。恕我直言,这是否有意义并不重要,因为列表仍然存在。那么我怎样才能 flatMap 呢?

标签: java java-8 java-stream


【解决方案1】:

实际上你的要求没有意义。您想按属性分组,这意味着它不一定是双射函数。因此,结果映射的值的类型默认为列表。如果您知道您应用的函数是双射的,您可以提供另一个下游收集器/或使用 toMap 收集器,将抛出合并器作为参数(最好的选择 IMO)。

例如:

Map<Integer, Person> list = 
    ss.stream()
      .collect(Collectors.toMap(p -> p.surname.length(), 
                                p -> p, 
                                (p1, p2) -> {throw new IllegalStateException("Duplicate key with length " + p1.surname.length());}));

您的情况下的输出:

{3=(John, Doe, 20), 4=(Bort, Bort, 30), 5=(Max, Power, 26), 7=(Scorpio, McGreat, 56)}

【讨论】:

  • 谢谢!我会试试这个。如果用例有点太混乱,我会改变它。正是我需要的。谢谢你好先生。
猜你喜欢
  • 2019-08-08
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-17
  • 2021-12-16
  • 2016-07-14
  • 1970-01-01
相关资源
最近更新 更多