1

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:

  1. Create a Map<Topic, Message> from messages list (done as you can see in the example below)
  2. 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)
  3. 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] 

1 Answer 1

2

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())));
Sign up to request clarification or add additional context in comments.

1 Comment

That is fantastic man. I have played around with flatmap but couldn't get it. Thank you very much.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.