1

let data =  [
{news: id1, users: [{user1}, {user2}, {user3}]},
{news: id2, users: [{user2}, {user4}, {user6}]},
{news: id3, users: [{user1}, {user2}, {user4}]}
]

So from the above data, I need to be able to group news items to form a template(let's consider a template consists strictly two news items). Then for every template, I need to match the corresponding user. Finally, when I'm done with creating all the templates I need to map remaining users to their respective news items.

I've added a sample output below

[id1,id2] : [user2]
[id2, id3] : [user2, user4]
[id3, id1] : [user1, user2]
[id2] : [user6]
[id1] : [user3]

How do I achieve this?

7
  • Question is not clear. Are you trying to create all the combinations ? Commented Dec 10, 2019 at 14:39
  • 1
    Please provide a minimal reproducible example not pseudo-data Commented Dec 10, 2019 at 14:40
  • why doesn't [id3] : [] exist and have a value in your result example? Is it because it does not have a distinct value? Commented Dec 10, 2019 at 14:42
  • @ViswanathLekshmanan, yes, it's actually a 3C2 combination on news, but that doesn't include all the users, so I need to pick up the remaining users and map them to their respective news items. Commented Dec 10, 2019 at 14:45
  • @Ivan86, that's because I'm grouping news as templates and every template contains exactly 2 news items. But for the remaining users, I need to map them to their respective news items Commented Dec 10, 2019 at 14:47

1 Answer 1

3

You could take a hash table and build the wanted structure by checking the length of the values and if greater than 2 take the combination of the values for adding the new grouups to the result set, instead of the given group.

var data = [{ news: 'id1', users: ['user1', 'user2', 'user3'] }, { news: 'id2', users: ['user2', 'user4', 'user6'] }, { news: 'id3', users: ['user1', 'user2', 'user4'] }],
    cool = data.reduce((r, { news, users }) => users.reduce((o, user) => ((o[user] = o[user] || []).push(news), o), r), {}),
    result = Object.entries(cool).reduce((r, [user, news]) => {
        function add(k, v) {
            var temp = r.find(([a]) => a.join('|') === v.join('|'));
            if (!temp) r.push(temp = [v, []]);
            temp[1].push(k);
        }

        if (news.length > 2) {
            news.reduce((r, v, i, a) => r.concat(a.slice(i + 1).map(w => [v, w])), [])
                .forEach(news => add(user, news));
        } else {
            add(user, news);
        }
        return r;
    }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

2 Comments

Very nice. +2 if I could.
Wow, this is precisely what I wanted, I need to clearly look into the solution. Because although I said that a template would contain 2 elements, it's actually 10 and the remaining users will end up with < 10 news items. Could be ranging anywhere between 0 and 9. 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.