Java 11:使用收集器将 List<String> 转换为 TreeMap<String, List<String>>

问题描述

我有一个这样的清单

List<String> customList = Arrays.asList(
   "5000  Buruli ulcer is an infectIoUs disease","6000  characterized by the development","7000  of painless open wounds.","8000  The disease largely occurs in","10000  sub-Saharan Africa and Australia."
);

我想将 List 转换成这样的 TreeMap<String,List<String>>

"5000",["Buruli","ulcer","is","an","infectIoUs","disease"]
"6000",["characterized","by","the","development"]
// etc

到目前为止我的代码

TreeMap<String,List<String[]>> collect = customList.stream()
      .map(s -> s.split("  ",2))
      .collect(Collectors
         .groupingBy(a -> a[0],TreeMap::new,Collectors.mapping(a -> a[1].split(" "),Collectors.toList())));

我有两个问题。

  1. 首先,TreeMap::new 可能不起作用,因为顺序与原始 List 的顺序不同。
  2. 其次是我似乎没有找到将 List<String[]> 变成 List<String>方法

有什么想法吗?

解决方法

您想使用 LinkedHashMap 来保留原始顺序。所以你的代码应该是这样的:

Map<String,List<String>> collect = customList.stream()
    .map(s -> s.split(" +"))
    .collect(Collectors.toMap(a -> a[0],a -> Arrays.asList(a)
        .subList(1,a.length),(a,b) -> a,LinkedHashMap::new));

如果您的键不是唯一的,您可以使用分组收集器进行类似的操作(Collectors.flatMapping 需要 Java 9+):

collect = customList.stream()
    .map(s -> Arrays.asList(s.split(" +")))
    .collect(Collectors.groupingBy(l -> l.get(0),LinkedHashMap::new,Collectors.flatMapping(l -> l.stream().skip(1),Collectors.toList())));
,

又一个更新:

此更新是为了满足 OP 在答案下方的评论中提到的以下要求:

我希望每个单词都作为列表中的一个单独元素。和你的 解决方案,所有元素都在同一个 List 条目中。例如,我 想要 10000=[撒哈拉以南、非洲和澳大利亚。]

为了实现这一点,您不应拆分单词串。

演示:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> customList = Arrays.asList(
                   "5000  Buruli ulcer is an infectious disease","6000  characterized by the development","7000  of painless open wounds.","8000  The disease largely occurs in","10000  sub-Saharan Africa and Australia."
                );
        
        TreeMap<String,List<String>> collect = customList.stream().map(s -> s.split("  ",2))
                .collect(Collectors.groupingBy(a -> a[0],() -> new TreeMap<String,List<String>>(Comparator.comparingInt(Integer::parseInt)),Collectors.mapping(a -> a[1],Collectors.toList())));
        
        System.out.println(collect);
    }
}

输出:

{5000=[Buruli ulcer is an infectious disease],6000=[characterized by the development],7000=[of painless open wounds.],8000=[The disease largely occurs in],10000=[sub-Saharan Africa and Australia.]}

或者基于我原来的答案:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> customList = Arrays.asList(
                   "5000  Buruli ulcer is an infectious disease","10000  sub-Saharan Africa and Australia."
                );

        Map<String,List<String>> collect = customList.stream().map(s -> s.split("\\s+",TreeMap::new,Collectors.toList())));

        System.out.println(collect);
    }
}

输出:

{10000=[sub-Saharan Africa and Australia.],5000=[Buruli ulcer is an infectious disease],8000=[The disease largely occurs in]}

Aniket 建议的解决方案:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> customList = Arrays.asList(
                   "5000  Buruli ulcer is an infectious disease",Collectors.mapping(a -> Arrays.toString(a[1].split(" ")),Collectors.toList())));

        System.out.println(collect);
    }
}

输出:

{5000=[[Buruli,ulcer,is,an,infectious,disease]],6000=[[characterized,by,the,development]],7000=[[of,painless,open,wounds.]],8000=[[The,disease,largely,occurs,in]],10000=[[sub-Saharan,Africa,and,Australia.]]}

原答案:

你快到了。你可以这样做:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> customList = Arrays.asList(
                   "5000  Buruli ulcer is an infectious disease","10000  sub-Saharan Africa and Australia."
                );

        Map<Object,List<Object>> collect = customList.stream().map(s -> s.split("\\s+",Collectors.mapping(a -> Arrays.asList(a[1].split("\\s+")),Collectors.toList())));

        System.out.println(collect);
    }
}

输出:

{10000=[[sub-Saharan,Australia.]],5000=[[Buruli,in]]}