英文:
How to Convert a Map<String, List<List<String>>> to Map<String, List<String>> in java 8 functional APIs
问题
我有一个这样的类;
class: {
   id: "",
   sub: [{
       type: 1,
       value: ""
   }]
}
现在,我想按id首先分组类;
class.stream().collect(Collectors.groupingBy(class::id))
然后我想将子值平铺到List<String>,我有以下内容:
class.stream().collect(Collectors.groupingBy(class::id,
  Collectors.mapping(e ->
    e.sub().stream()
      .filter(v -> v.type().equals(1))
       .map(sub::value),
    Collectors.toList()
  )))
它返回一个Map<String, List<List<String>>>
那么,我如何将Map<String, List<List<String>>>转换为Map<String, List<String>>,使用Java 8函数API?
英文:
I have a class like this;
class: {
   id: "",
   sub: [{
       type: 1,
       value: ""
   }]
}
Now, I want group class first by id;
class.stream().collect(Collectors.groupingBy(class::id))
Then I want flat sub-value to a List<String>, I have the following:
class.stream().collect(Collectors.groupingBy(class::id,
  Collectors.mapping(e ->
    e.sub().stream()
      .filter(v -> v.type().equals(1))
       .map(sub::value),
    Collectors.toList()
  )))
It returns a Map<String, List<List<String>>>
So, how can I convert a Map<String, List<List<String>>> to Map<String, List<String>> using the Java 8 functional API?
答案1
得分: 1
您可以使用Map收集器按键分组并合并值。
示例(Java 14及以上):
class Test {
	// 示例数据类型
	record Sub(int type, String value) {}
    record Clazz(String id, List<Sub> sub) {}
	public static void main(String[] args) {
		// 示例数据
		List<Clazz> classes = List.of(
			new Clazz("id1", List.of(new Sub(1, "A"), new Sub(2, "B"))),
			new Clazz("id2", List.of(new Sub(3, "C"), new Sub(4, "D"))),
			new Clazz("id1", List.of(new Sub(5, "E"), new Sub(6, "A")))
		);
		Map<String, List<String>> map = classes.stream()
			.collect(Collectors.toMap(
				// 新地图的键: c.id
				c -> c.id,
				// 新地图的值: c.sub[].value 作为列表
				c -> c.sub.stream().map(s -> s.value).toList(),
				// 重复值合并(分组): 合并两个值列表,无重复项
				(v1, v2) -> Stream.concat(v1.stream(), v2.stream()).distinct().toList()
			));
		// 打印生成的数据
		map.forEach((k, v) -> System.out.println(k + " -> " + String.join(",", v)));
	}
}
输出:
id2 -> C,D
id1 -> A,B,E
英文:
You can use the Map collector to group by keys and merge the values.
Example (Java 14 & above):
class Test {
	// sample data types
	record Sub ( int type, String value ){}
    record Clazz (String id, List<Sub> sub){}
	public static void main(String[] args)
	{
		// sample data
		List<Clazz> classes = List.of(
			new Clazz("id1",List.of(new Sub(1,"A"),new Sub(2,"B"))),
			new Clazz("id2",List.of(new Sub(3,"C"),new Sub(4,"D"))),
			new Clazz("id1",List.of(new Sub(5,"E"),new Sub(6,"A")))
		);
		Map<String, List<String>> map = classes.stream()
			.collect(Collectors.toMap(
				// key for new map: c.id
				c -> c.id,
				
				// value for new map: c.sub[].value as a list
				c -> c.sub.stream().map(s -> s.value).toList(),
				
				// duplicate value merging (grouping) : merge two value lists, no duplicates
				(v1, v2) -> Stream.concat(v1.stream(), v2.stream()).distinct().toList()
			));
		// print resulting data
		map.forEach((k,v) -> System.out.println(k + "\t->\t" + String.join(",", v)));
	}
}
Output:
id2	->	C,D
id1	->	A,B,E
答案2
得分: 0
就像@Sametcey建议的那样,您可以使用flatMap。
每当遇到使用嵌套列表的情况(就像您的Map<String,List<List>>一样,但也可以在更深层次上使用,如Map<String,List<List<List>>>),flatMap会对此进行帮助。
它会将您的流转换为一个单一的扁平流。换句话说:一个可以访问和操作的列表。
英文:
Just like @Sametcey suggested you can use flatMap.<br> Whenever you encounter something that uses nested lists (just like your Map<String, List<List>>, but it's possible to use it on deeper level like Map<String, List<List<List>>>) flatMap will help you with that.
It will transform your stream into a single flattened stream. In other words: one list that you can access and manipulate.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论