Java Stream Collectors.groupingBy分组问题及泛型方法实现咨询
解决按单个Organ分组及泛型分组方法的问题
嘿,我来帮你搞定这两个问题——先解决你当前按单个器官分组的问题,再实现通用的泛型分组方法。
一、按单个Organ分组得到Map<String, List<Foo>>
你现在的代码之所以返回Map<Object, List<Foo>>,而且键是整个器官列表,是因为groupingBy(x -> x.getOrgan())把整个List<String>当成了分组键。要实现每个单独器官作为键,我们得先把每个Foo和它的每个器官一一对应,再分组:
正确实现代码
import java.util.List; import java.util.Map; import java.util.AbstractMap; import java.util.stream.Collectors; // 确保Foo类有getOrgans()和getCassette()的getter方法 Map<String, List<Foo>> organToFoosMap = fooList.stream() // 把每个Foo拆分成(器官,Foo)的流元素,每个器官对应原Foo .flatMap(foo -> foo.getOrgans().stream() .map(organ -> new AbstractMap.SimpleEntry<>(organ, foo))) // 按器官字符串分组,收集对应的Foo列表 .collect(Collectors.groupingBy( Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toList()) ));
效果示例
假设你的fooList是:
List<Foo> fooList = List.of( new Foo("1A", List.of("Lung", "Liver")), new Foo("2A", List.of("Liver")) );
运行后得到的结果会是:
{Lung=[Foo [cassette=1A, organs=[Lung, Liver]]], Liver=[Foo [cassette=1A, organs=[Lung, Liver]], Foo [cassette=2A, organs=[Liver]]]}
完全符合你要的——每个单独器官作为键,对应所有包含该器官的Foo对象。
二、实现泛型分组方法
如果你需要一个通用方法,只要传入分组键的提取逻辑,就能返回Map<String, List<Foo>>,可以分两种情况实现:一种是针对单一值的分组(比如按cassette),另一种是针对多值列表的分组(比如按organs)。
1. 单一值分组的泛型方法
这个方法适用于提取单个值作为分组键的场景(比如cassette字段):
import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; public class FooGroupingHelper { /** * 按指定的单一键对Foo列表分组,返回键为String类型的Map * @param fooList 待分组的Foo列表 * @param keyExtractor 提取分组键的函数,返回值会自动转为String * @param <T> 分组键的原始类型 * @return 分组后的Map<String, List<Foo>> */ public static <T> Map<String, List<Foo>> groupFoosBySingleKey(List<Foo> fooList, Function<Foo, T> keyExtractor) { return fooList.stream() .collect(Collectors.groupingBy( foo -> String.valueOf(keyExtractor.apply(foo)), Collectors.toList() )); } }
使用示例
按cassette分组:
Map<String, List<Foo>> cassetteGroup = FooGroupingHelper.groupFoosBySingleKey(fooList, Foo::getCassette);
2. 多值列表分组的泛型方法
这个方法专门处理像organs这种多值列表的场景,把列表里的每个元素作为单独的分组键:
import java.util.List; import java.util.Map; import java.util.AbstractMap; import java.util.function.Function; import java.util.stream.Collectors; public class FooGroupingHelper { // ... 上面的单一值方法 ... /** * 按Foo中的多值列表分组,每个列表元素作为单独的键 * @param fooList 待分组的Foo列表 * @param multiValueExtractor 提取多值列表的函数,列表元素会转为String作为键 * @param <T> 列表元素的原始类型 * @return 分组后的Map<String, List<Foo>> */ public static <T> Map<String, List<Foo>> groupFoosByMultiValue(List<Foo> fooList, Function<Foo, List<T>> multiValueExtractor) { return fooList.stream() .flatMap(foo -> multiValueExtractor.apply(foo).stream() .map(value -> new AbstractMap.SimpleEntry<>(String.valueOf(value), foo))) .collect(Collectors.groupingBy( Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toList()) )); } }
使用示例
按器官分组:
Map<String, List<Foo>> organGroup = FooGroupingHelper.groupFoosByMultiValue(fooList, Foo::getOrgans);
这样你就可以根据不同的分组需求,灵活调用对应的泛型方法啦。
内容的提问来源于stack exchange,提问作者I'm_Pratik
相关产品推荐
相关产品推荐

