Reputation: 1161
I have the following array of objects:
[
{
"id": "5ffcab3a065d103265f92bfc",
"label": "Test Group 1",
"channels": [
"44332"
]
},
{
"id": "5f85362e573c400e91bb7b15",
"label": "Test Group 2",
"channels": [
"85705",
"87984"
]
}
]
I am trying to relate objects by their channels
values. If two objects share the same value in their channels
array, I would like their ids to be output.
Upvotes: 1
Views: 62
Reputation: 350137
First of all we note that this relation (of sharing a common channel) is not transitive:
if A relates to B and B relates to C, it does not follow that A relates to C.
The relation is however commutative:
if A relates to B, then B relates to A.
So, a possible useful output could be a list of sorted pairs of ids. We cannot hope to group them into larger groups, as then the lack of transitivity poses problems.
In order to extract these pairs, you could first group ids per channel, i.e. for each channel you would have a list of ids.
Then the solution consists of each possible sorted pair you can take from the same list. I say sorted, because reversed pairs do not give additional information, due to the commutative nature of the relation, so these can be excluded.
Duplicate pairs should be removed from the result.
For this we can make use of Maps and Sets:
// Some example data
let data = [
{ id: "a", channels: [1, 2, 3] },
{ id: "b", channels: [2, 4, 6] },
{ id: "c", channels: [3, 6, 9] },
{ id: "d", channels: [4, 8, 12] },
{ id: "e", channels: [5, 10, 15] },
]
// Get the object ids grouped per channel
let temp = data.flatMap(({id, channels}) => channels.map(channel => [channel, id]));
let map = new Map(temp.map(([channel]) => [channel, []]));
for (let [channel, id] of temp) map.get(channel).push(id);
// Create unique pairs of connected ids
let set = new Set(Array.from(map.values(), ids =>
ids.map(id =>
ids.map(id2 => id < id2 && JSON.stringify([id, id2]))
)
).flat(2).filter(Boolean));
// Extract result
let result = Array.from(set, JSON.parse);
console.log(result);
Upvotes: 3