1 回答

TA貢獻(xiàn)1859條經(jīng)驗(yàn) 獲得超6個(gè)贊
回答這個(gè)問(wèn)題的話,我們可以先來(lái)看看為啥會(huì)出現(xiàn)Map<String, List<List<String>>>
的結(jié)果,這要從Collectors.groupingBy
的設(shè)計(jì)語(yǔ)義來(lái)說(shuō)了,它代表把流的數(shù)據(jù)按照一定規(guī)則進(jìn)行歸類分組,并要求提供同一組的數(shù)據(jù)怎么進(jìn)行收集的方法,所以這就是Collectors.groupingBy
兩個(gè)參數(shù)的含義
那題主第一個(gè)參數(shù)寫的是Condition::getCondName
,代表流的Condition
按照其condName
屬性進(jìn)行分組,分組之后,同一組的Condition
如何處理,這里題主用的Collectors.mapping(Condition::getCondValue, Collectors.toList()))
,mapping
代表映射轉(zhuǎn)換,這里有點(diǎn)類似分組,Collectors.mapping
第一個(gè)參數(shù)把流的Condition
轉(zhuǎn)化為List<String>
,此時(shí)流里就是List<String>
,再經(jīng)過(guò)第二個(gè)參數(shù)Collectors.toList()
,哦豁,當(dāng)然最后結(jié)果就是List<List<String>>
這里題主得不到答案的原因就是Collectors.mapping
的第二個(gè)參數(shù)沒(méi)有寫對(duì),我這里想到三種方式
第一種:還是用Collectors.mapping
,類似題主提到的再遍歷一遍,哈哈
Map<String, List<String>> collect = conditions.stream()
.collect(Collectors.groupingBy(Condition::getCondName,
Collectors.mapping(Condition::getCondValue,
Collectors.collectingAndThen(Collectors.toList(), lists -> lists.stream().flatMap(List::stream).collect(Collectors.toList())))));
這里Collectors.mapping
的第二個(gè)參數(shù)用了Collectors.collectingAndThen
,從名字就看得出來(lái),收集好了之后再做什么事...第一個(gè)參數(shù)當(dāng)然還是按照Collectors.toList()
,收集到之后,第二個(gè)參數(shù)再把List
遍歷一次,壓平后再組成List
emmm,我也不太喜歡這種,不過(guò)只是引出了哈collectingAndThen
,說(shuō)不定以后題主可以用到
第二種:也還是用Collectors.mapping
,不過(guò)這次第二個(gè)參數(shù)用Collectors.reducing
Map<String, List<String>> collect2 = conditions.stream()
.collect(Collectors.groupingBy(Condition::getCondName,
Collectors.mapping(Condition::getCondValue,
Collectors.reducing(new ArrayList<>(), (l1, l2) -> Stream.concat(l1.stream(), l2.stream()).collect(Collectors.toList())))));
這里的Collectors.reducing
就是數(shù)據(jù)的聚合,正好也符合當(dāng)前的場(chǎng)景,當(dāng)流里的數(shù)據(jù)由Condition
轉(zhuǎn)化為List<String>
時(shí),我們就是要找到一種合并不同List<String>
的方法,所以這里用到這個(gè)聚合方法Collectors.reducing
,第一個(gè)參數(shù)是起始值,第二個(gè)參數(shù)代表怎么合并兩個(gè)list
第二個(gè)方法要好一點(diǎn),不過(guò)這里我還想到第三個(gè)方法
第三種:不用Collectors.groupingBy
,而采用Collectors.toMap
Map<String, List<String>> collect1 = conditions.stream().collect(
Collectors.toMap(Condition::getCondName, Condition::getCondValue, (c1, c2) -> Stream.concat(c1.stream(), c2.stream()).collect(Collectors.toList())));
第三種方式感覺(jué)要比前兩種簡(jiǎn)單點(diǎn),但是這是巧用了哈toMap
方法,toMap
方法一般使用在數(shù)據(jù)能夠有一種一對(duì)一的關(guān)系時(shí)才用,大多數(shù)的時(shí)候我們一般也只使用兩個(gè)參數(shù)的方法,即傳入怎么獲取map
的key
和怎么獲取map
的value
的兩個(gè)Function
,因?yàn)橐话闱闆r下,業(yè)務(wù)上可以保證數(shù)據(jù)是具有一對(duì)一的關(guān)系的,如果只是調(diào)用兩參方法,但是實(shí)際使用過(guò)程中,確實(shí)出現(xiàn)了一對(duì)多的情況,那么這時(shí)候調(diào)用toMap
兩參方法是會(huì)報(bào)錯(cuò)的,因此就有了toMap
這個(gè)三參方法,第三個(gè)參數(shù)代表怎么合并同一個(gè)key
的value
值,所以到了這里就跟第二種方法的思路差不多了,合并兩個(gè)集合即可
以上就是我的回答,僅供參考
對(duì)了,再加一點(diǎn),我一般是不太喜歡在流里寫過(guò)長(zhǎng)的lambda表達(dá)式的,因?yàn)榱骼锸且w現(xiàn)當(dāng)前流程的,不是爛七八糟的都往里噻,所以第三種方式,最后的集合合并,最好還是寫成一個(gè)BinaryOperator
,畢竟現(xiàn)在方法也可以是一種參數(shù)或者屬性了嘛
public static final BinaryOperator<List<String>> listMergeMethod = (l1, l2) -> Stream.concat(l1.stream(), l2.stream()).collect(Collectors.toList());
Map<String, List<String>> collect1 = conditions.stream().collect(
Collectors.toMap(Condition::getCondName, Condition::getCondValue, listMergeMethod));
這樣我感覺(jué)要順點(diǎn)。。。
添加回答
舉報(bào)