我在google上搜索了一下,但我发现大多数情况下都是通过聚合字段进行分组,或者改变流的响应,但不是下面的场景:
我有一节课 User
带字段 category
以及 marketingChannel
.
我必须以声明式风格编写一个方法,该方法接受用户列表并根据 category
也基于 marketingChannel
单独(即不 groupingBy(... ,groupingBy(..))
).
我不能在一个循环中完成它。这就是我要达到的目标。
我将几种方法编码如下:
import java.util.*;
import java.util.stream.*;
public class Main
{
public static void main(String[] args) {
List<User> users = User.createDemoList();
imperative(users);
declerativeMultipleLoop(users);
declerativeMultipleColumn(users);
}
public static void imperative(List<User> users){
Map<String, Integer> categoryMap = new HashMap<>();
Map<String, Integer> channelMap = new HashMap<>();
for(User user : users){
Integer value = categoryMap.getOrDefault(user.getCategory(), 0);
categoryMap.put(user.getCategory(), value+1);
value = channelMap.getOrDefault(user.getMarketingChannel(), 0);
channelMap.put(user.getMarketingChannel(), value+1);
}
System.out.println("imperative");
System.out.println(categoryMap);
System.out.println(channelMap);
}
public static void declerativeMultipleLoop(List<User> users){
Map<String, Long> categoryMap = users.stream()
.collect(Collectors.groupingBy(
User::getCategory, Collectors.counting()));
Map<String, Long> channelMap = users.stream()
.collect(Collectors.groupingBy(
User::getMarketingChannel, Collectors.counting()));
System.out.println("declerativeMultipleLoop");
System.out.println(categoryMap);
System.out.println(channelMap);
}
public static void declerativeMultipleColumn(List<User> users){
Map<String, Map<String, Long>> map = users.stream()
.collect(Collectors.groupingBy(
User::getCategory,
Collectors.groupingBy(User::getMarketingChannel,
Collectors.counting())));
System.out.println("declerativeMultipleColumn");
System.out.println("groupingBy category and marketChannel");
System.out.println(map);
Map<String, Long> categoryMap = new HashMap<>();
Map<String, Long> channelMap = new HashMap<>();
for (Map.Entry<String, Map<String, Long>> entry: map.entrySet()) {
String category = entry.getKey();
Integer count = entry.getValue().size();
Long value = categoryMap.getOrDefault(category,0L);
categoryMap.put(category, value+count);
for (Map.Entry<String, Long> channelEntry : entry.getValue().entrySet()){
String channel = channelEntry.getKey();
Long channelCount = channelEntry.getValue();
Long channelValue = channelMap.getOrDefault(channel,0L);
channelMap.put(channel, channelValue+channelCount);
}
}
System.out.println("After Implerative Loop on above.");
System.out.println(categoryMap);
System.out.println(channelMap);
}
}
class User{
private String name;
private String category;
private String marketChannel;
public User(String name, String category, String marketChannel){
this.name = name;
this.category = category;
this.marketChannel = marketChannel;
}
public String getName(){
return this.name;
}
public String getCategory(){
return this.category;
}
public String getMarketingChannel(){
return this.marketChannel;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(name, user.name) &&
Objects.equals(category, user.category) &&
Objects.equals(marketChannel, user.marketChannel);
}
@Override
public int hashCode() {
return Objects.hash(name, category, marketChannel);
}
public static List<User> createDemoList(){
return Arrays.asList(
new User("a", "student","google"),
new User("b", "student","bing"),
new User("c", "business","google"),
new User("d", "business", "direct")
);
}
方法 declerativeMultipleLoop
是声明性的,但每个字段都有一个单独的循环。复杂性:o(nooffields*用户数)
问题出在 declerativeMultipleColumn
方法,因为我最终编写了命令式代码和多个循环。
我想用完全声明的方式编写上述方法,并且尽可能高效。i、 e复杂性:o(用户数)
样本输出:
命令
{业务=2,学生=2}
{direct=1,google=2,bing=1}
减容多路环路
{业务=2,学生=2}
{direct=1,google=2,bing=1}
减容多重柱
按类别和市场渠道分组
{business={direct=1,google=1},student={google=1,bing=1}}
在上面的内爆循环之后。
{业务=2,学生=2}
{direct=1,google=2,bing=1}
1条答案
按热度按时间gtlvzcf81#
如果我了解你的要求,它是使用一个单一的流操作,结果在两个单独的Map。这将需要一个结构来保存Map,并需要一个收集器来构建结构。如下所示:
然后可以用作收集器:
(仅观点:在这种情况下,命令式和声明式之间的区别是相当武断的。定义流操作对我来说是非常程序化的(与haskell中的等价操作相反)。