我正在编写一些代码,我需要将具有嵌套集合字段的对象转换为基于这些集合的对象列表。我的起始对象如下所示:
public class Attributes{
public String id;
public List<String> optIn;
public List<String> emailNotifications;
}
我需要将该对象转换为该类的对象列表:
public class LearnerSubscription{
public String id;
public String channel;
public boolean dailyEmails;
public boolean individualEmails;
}
作为示例,假设一个具有以下数据的 Attributes 对象:
Attribute atr1 = new Attribute();
atr1.id="1";
atr1.optIn=List.of("abc", "xyz", "123");
atr1.emailNotifications=List.of("abc", "123", "trp");
当我运行转换函数时,我想得到以下输出:
[ LearnerSubscription("1", "abc", true, true),
LearnerSubscription("1", "xyz", true, false),
LearnerSubscription("1", "123", true, true),
LearnerSubscription("1", "trp", false, true) ]
请注意如何根据通道是否出现在第一个列表(“xyz”)、第二个列表(“trp”)或两者(“abc”、“123”)中来计算布尔值。
我不确定实现这样的功能的最佳方法是什么。我知道我可以简单地暴力破解它;迭代 optIn 和 emailNotifications 中的所有项目并跟踪常见项目。然而,我觉得应该有一个更优雅的解决方案,利用 Java Stream API。对于解决问题的更好方法有什么建议吗?
现在如何给出?不,除了使用 for 循环循环遍历每个选项并在找到它时打破循环之外,没有更快的方法了。但是,如果您的列表是哈希的排序集合,您可以对哈希项进行二分搜索,这会将时间效率提高到 O(log(n))。
我们快速分析一下一般需要哪些操作:
使用流 API,使用上面的代码,它可能看起来像这样(可能还有更优雅的方法):
Collection<Optional<LearnerSubscription>> subs = Stream.of(atr1)
//flatten each attribute into a stream of subscriptions
.flatMap(atr -> Stream.concat(
//a stream for daily subscriptions
atr.optIn.stream().map(c -> new LearnerSubscription(atr.id, c, true, false)),
//a stream for individual subscriptions
atr.emailNotifications.stream().map(c -> new LearnerSubscription(atr.id, c, false, true))
))
//collect by grouping on attribute id and channel
.collect(Collectors.groupingBy(s -> Pair.of(s.id, s.channel),
//reduce by merging subscription a into b
Collectors.reducing((a, b) -> {
a.dailyEmails |= b.dailyEmails;
a.individualEmails |= b.individualEmails;
return a;
})))
//just get the values of the group map (this could further be converted into a list)
.values();
但是,使用流可能并不容易阅读和理解,也不一定更快。
使用循环和映射可能是更好的方法:
(示例即将到来)