Context:
I have a Topic
enum:
public enum Topic {
RELATIONSHIP, DATING, EDUCATION, FITNESS, NEWS, RENT, EVENTS, GIVEAWAY, SALE
}
and a class Member with a topics list as field. A member has at least one and up to 9 topics, to which he/she has subscribed.
@AllArgsConstructor
@Getter
@ToString
static class Member {
String id;
List<Topic> topics;
String email;
}
Once a week I get a list of Messages. Each messages belongs to exactly one Topic type. The list of Messages doesn't contain Messages, which have the same topic (no duplicate topics and never empty, 1 to 9 entries)
@AllArgsConstructor
@Getter
@ToString
static class Message {
String id;
Topic topic;
String content;
}
Question:
Given a list of messages and a list of members create a map Map<Message, List<Member>>
to be used to send each member a notification. Each member should only receive notifications for topics, to which he/she has subscribed.
My approach:
- Create a
Map<Topic, Message>
from messages list (done as you can see in the example below) - Create a
Map<Topic, List<Member>>
from members list. (I am stuck here, don't know how to extract single Topics from members topic list to create my desired map) - after I get the above two maps create a final map
<Message, List<Member>>
mapping the values of first map to corresponding values of second map. Should be easy.
Example setup:
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
public class Example {
public static void main(String[] args) {
List<Message> messages = List.of(new Message("KW41",Topic.EDUCATION,"Some educational content published"),
new Message("KW41",Topic.FITNESS,"Some fitness content published"),
new Message("KW41",Topic.DATING,"Some dating content published"),
new Message("KW41",Topic.RENT,"Some rent content published"));
List<Member> memberList = List.of(new Member("1", List.of(Topic.SALE, Topic.RENT), "[email protected]"),
new Member("2", List.of(Topic.DATING, Topic.NEWS), "[email protected]"),
new Member("3", List.of(Topic.EDUCATION), "[email protected]"),
new Member("4", List.of(Topic.FITNESS, Topic.RENT, Topic.EDUCATION), "[email protected]"),
new Member("5", List.of(Topic.RELATIONSHIP), "[email protected]"),
new Member("6", List.of(Topic.SALE, Topic.NEWS), "[email protected]"),
new Member("7", List.of(Topic.NEWS, Topic.EVENTS), "[email protected]"));
Map<Topic,Message> messageMap = messages.stream().collect(Collectors.toMap(Message::getTopic, Function.identity()));
messageMap.entrySet().forEach(System.out::println);
}
@AllArgsConstructor
@Getter
@ToString
static class Member {
String id;
List<Topic> topics;
String email;
}
@AllArgsConstructor
@Getter
@ToString
static class Message {
String id;
Topic topic;
String content;
}
enum Topic {
RELATIONSHIP, DATING, EDUCATION, FITNESS, NEWS, RENT, EVENTS, GIVEAWAY, SALE
}
}
How can i get from the members list a Map<Topic, List<Member>>
grouped by topics. (I cant't easily do stream.collect(Collectors.groupingBy(Member::getTopics))
since it is a list. I need to extract them somehow before). Desired map should contain (adding only members ids for readability)
Topic.RELATIONSHIP=[5]
Topic.DATING=[2]
Topic.EDUCATION=[3, 4]
Topic.FITNESS=[4]
Topic.NEWS=[2, 6, 7]
Topic.RENT=[1, 4]
Topic.EVENTS=[7]
Topic.SALE=[1, 6]
CodePudding user response:
Flattening into tuples could help.
For example with:
@Value
class Tuple<L, R> {
L left;
R right;
}
You could have:
Stream<Member> stream = ...;
Map<Topic, List<Member>> result = stream
.flatMap(member -> member.getTopics().stream().map(topic -> new Tuple<>(topic, member)))
.collect(groupingBy(Tuple::getLeft, mapping(Tuple::getRight, toList())));