如何使用Java Stream将LIst<Object>转换为Map<K,V>:

huangapple go评论76阅读模式
英文:

How to convert LIst<Object> to Map<K, V> with using java stream

问题

我想将 `List&lt;ObjectInList&gt;` 转换成 `Map&lt;K, V&gt;`

class ObjectInList {
    List&lt;Long&gt; listWithLong;
    Map&lt;String, Object&gt; dataMap; // 这里有一个 'id' 键,我想要将这个 id 作为转换后的映射中的键
}

新的映射格式如下
String type; // 这个 type 是 dataMap 的值
List&lt;Long&gt; contents

List&lt;Object&gt; 中的每个对象可以有重复的 type

例如

///////// 转换前 ////////////
[
 {
    list: [1,2,3],
    dataMap: {
      type: "a",
    }
 },
 {
    list: [4,5,6],
    dataMap: {
      type: "b",
    }
 },
 {
    list: [7,8],
    dataMap: {
      type: "a",
    }
 },
]
///////////// 转换后 //////////
{
  "a": [1,2,3,7,8],
  "b": [4,5,6]
}

<details>
<summary>英文:</summary>

I want to convert `List&lt;ObjectInList&gt;` to `Map&lt;K, V&gt;`

class ObjectInList {
List<Long> listWithLong;
Map<String, Object> dataMap; // there is 'id' key, and i want to use this id as key in map to be converted
}

The new map format is like below

String type; // this type is value of dataMap.
List<Long> contents

each Object in `List&lt;Object&gt;` can have duplicated type

for example

///////// before converted ////////////
[
{
list: [1,2,3],
dataMap: {
type: "a",
}
},
{
list: [4,5,6],
dataMap: {
type: "b",
}
},
{
list: [7,8],
dataMap: {
type: "a",
}
},
]
///////////// after converted //////////
{
"a": [1,2,3,7,8],
"b": [4,5,6]
}




</details>


# 答案1
**得分**: 1

你可以使用`groupingBy`按`type`进行分组,并且使用`flatMapping`来展平`Long`数据的列表,并将其收集为单个列表。

```java
Map<String, List<Long>> res = 
   objectInList
    .stream()
    .collect(Collectors.groupingBy(
                       e -> e.getDataMap().get("type"),
                       Collectors.flatMapping(
                                  e -> e.getListWithLong().stream(),
                                  Collectors.toList())
     ));
英文:

You can use groupingBy to group by type and flatMapping to flatten list of Long data and collect as single list.

Map&lt;String, List&lt;Long&gt;&gt; res = 
   objectInList
    .stream()
    .collect(Collectors.groupingBy(
                       e -&gt; e.getDataMap().get(&quot;type&quot;),
                       Collectors.flatMapping(
                                  e -&gt; e.getListWithLong().stream(),
                                  Collectors.toList())
     ));

答案2

得分: 0

我不确定为什么你需要 Map<String, Object> dataMap;,当它本应只有一个值。为了简单起见,我已经修改了你的 ObjectInList 类如下:

class ObjectInList {
  List<Long> listWithLong;
  String type; 
}

要获得分组列表,我们可以这样做:

Map<String, List<Long>> grouped =
    objectInLists.stream()
        .collect(
            Collectors.toMap(
                ObjectInList::getType,
                ObjectInList::getListWithLong,
                (oldList, newList) -> {
                  oldList.addAll(newList);
                  return oldList;
                }));

解释:

toMap 方法 -

public static <T, K, U>
    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper,
                                    BinaryOperator<U> mergeFunction)

toMap 接受 keyMapper,这里是 ObjectInList::getType(根据类型进行分组),valueMapperObjectInList::getListWithLong,由于我们有重复的键,我们需要提供一个 mergeFunction,即 (oldList, newList) -> {oldList.addAll(newList); return oldList;}

根据文档:

一个合并函数,用于解决与同一键关联的值之间的冲突,如提供给 {@link Map#merge(Object, Object, BiFunction)}。

英文:

I'm not sure why do you need Map&lt;String, Object&gt; dataMap; when it was supposed to have only one value. For simplicity, I have modified your ObjectInList class as

class ObjectInList {
  List&lt;Long&gt; listWithLong;
  String type; 
}

To get grouped list we can do -

Map&lt;String, List&lt;Long&gt;&gt; grouped =
    objectInLists.stream()
        .collect(
            Collectors.toMap(
                ObjectInList::getType,
                ObjectInList::getListWithLong,
                (oldList, newList) -&gt; {
                  oldList.addAll(newList);
                  return oldList;
                }));

Explanation:

toMap method -

public static &lt;T, K, U&gt;
    Collector&lt;T, ?, Map&lt;K,U&gt;&gt; toMap(Function&lt;? super T, ? extends K&gt; keyMapper,
                                    Function&lt;? super T, ? extends U&gt; valueMapper,
                                    BinaryOperator&lt;U&gt; mergeFunction)

toMap takes keyMapper which is ObjectInList::getType (to group based on type) and valueMaper is ObjectInList::getListWithLongand as we have duplicate key we need to provide a mergeFunction as (oldList, newList) -&gt; {oldList.addAll(newList);return oldList;}

From documentation -

> a merge function, used to resolve collisions between values associated
> with the same key, as supplied to {@link Map#merge(Object, Object,
> BiFunction)

huangapple
  • 本文由 发表于 2020年8月17日 23:01:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/63453496.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定