如何将列表转换为Map Map <String,Map <String,Object >>

时间:2019-10-17 07:06:45

标签: java collections hashmap java-stream collectors

我有一个<LinearLayout android:id="@+id/remote_button_layout" android:layout_width="match_parent" android:layout_height="55dp" android:layout_marginStart="20dp" android:layout_marginEnd="20dp" android:layout_marginTop="30dp" android:background="@drawable/btn_remote_button" android:orientation="horizontal"> <TextView android:text="Example Text" android:textSize="10sp" android:fontFamily="@font/mmedium" android:textAllCaps="false" android:layout_width="125dp" android:layout_height="match_parent" android:gravity="center" android:textColor="@android:color/secondary_text_light"/> <Button android:id="@+id/btn_remote_button" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="40dp" android:layout_height="match_parent" android:layout_marginEnd="5dp" android:background="@drawable/btn_remote_button" android:drawableStart="@drawable/logo" app:layout_constraintHorizontal_bias="1.0" /> </LinearLayout> e想要转换为 List<Employee>,其中外部字符串应为“名称”,内部字符串应为“域”。

Map<String, Map<String,Emp>>

我尝试了以下操作-

       Name Id Domain
e(0) - Emp1, 1, Insurance
e(1) - Emp1, 2, Sales
e(2) - Emp2, 3, Sales
e(3) - Emp4, 4, Marketing

因此预期的输出图应该看起来像

e.stream().collect(Collectors.groupingBy(
                                   Employee::getName,
                                   toMap(Employee::getDomain,Emp)));

但是我只能得到唯一的值,实际输出-

<Emp1>
     <Insurance, e(0)>
     <Sales, e(1)>
<Emp2>
     <Sales, e(2)>
<Emp4>
     <Marketing, e(3)>

有人可以告诉最好的方法吗?

2 个答案:

答案 0 :(得分:1)

您最需要的是嵌套分组,例如:

Map<String, Map<String, List<Employee>>> groupedMap = employees.stream()
        .collect(Collectors.groupingBy(Employee::getName,
                Collectors.groupingBy(Employee::getDomain, Collectors.toList())));

注意-值为List<Employee>,它们是按名称然后按域分组的员工。 (两个都合并成一个列表。)


如果您要严格遵守与指定分组相对应的单个雇员的做法,则只需进行少量修改即可对我的代码起作用:

Map<String, Map<String, Employee>> groupedReducedMap = employees.stream()
        .collect(Collectors.groupingBy(Employee::getName,
                Collectors.toMap(Employee::getDomain,
                        Function.identity(), // value as the employee instance
                        (a, b) -> a))); // choose first instance for similar 'domain'

答案 1 :(得分:0)

由于输出应为Map<String, Map<String,Employee>>而不是Map<String, Map<String,List<Employee>>>(即,根据您请求的输出,不能有两个Employee具有相同的名称和相同的域),因此您可以将两个groupingBy链接起来,然后使用reducing确保每个内部组将只有一个Employee而不是List<Employee>

Map<String, Map<String,Optional<Employee>>> output =
    e.stream()
     .collect(Collectors.groupingBy(Employee::getName,
                                    Collectors.groupingBy(Employee::getDomain,
                                                          Collectors.reducing((x1,x2)->x2))));

此版本reducing的问题在于,即使我们知道Optional<Employee>永远不会为空,它也会返回Employee而不是Optional

我们可以通过以下方法解决此问题:

  Map<String, Map<String,Employee>> output =
      e.stream()
       .collect(Collectors.groupingBy(Employee::getName,
                                      Collectors.groupingBy(Employee::getDomain,
                                                            Collectors.reducing(e.get(0),
                                                                                (x1,x2)->x2))));

现在,我们使用具有标识值的reducing的变体,向其传递任意Employee实例(这无关紧要,因为它将始终被正确的实例替换) )。