Basic idea is to do the following steps:
1) The original input map.
+------+--------------+
| Keys | Values |
+------+--------------+
| M1 | [A1, A3] |
+------+--------------+
| M2 | [A1, A2, A3] |
+------+--------------+
| M3 | [A1, A2] |
+------+--------------+
| M4 | [A2, A3] |
+------+--------------+
2) Expanding the mapping in the following manner. Idea is to break the values into subsets so that we can group keys on the basis of values. eg: [A1, A3]
present in both M1
& M2
represents [A1, A3]
being common in both lists.
+------+--------------+-----------------------------+
| Keys | Values | |
+------+--------------+-----------------------------+
| M1 | [A1, A3] | |
+------+--------------+-----------------------------+
| M2 | [A1, A2, A3] | Expanding this entry |
+------+--------------+ to create a mapping +
| M2 | [A1, A2] | of this key i.e. M2 with |
+------+--------------+ all the possible +
| M2 | [A1, A3] | combinations of the |
+------+--------------+ original value [A1, A2, A3] +
| M2 | [A2, A3] | |
+------+--------------+-----------------------------+
| M3 | [A1, A2] | |
+------+--------------+-----------------------------+
| M4 | [A2, A3] | |
+------+--------------+-----------------------------+
3) Inverting the above mapping for doing groupBy on the new keys.
+--------------+--------+
| Keys | Values |
+--------------+--------+
| [A1, A3] | M1 |
+--------------+--------+
| [A1, A2, A3] | M2 |
+--------------+--------+
| [A1, A2] | M2 |
+--------------+--------+
| [A1, A3] | M2 |
+--------------+--------+
| [A2, A3] | M2 |
+--------------+--------+
| [A1, A2] | M3 |
+--------------+--------+
| [A2, A3] | M4 |
+--------------+--------+
4) An inverted map with keys as the common elements & values as their corresponding keys.
+--------------+---------+
| Keys | Values |
+--------------+---------+
| [A1, A3] | [M1,M2] |
+--------------+---------+
| [A1, A2, A3] | [M2] |
+--------------+---------+
| [A1, A2] | [M2,M3] |
+--------------+---------+
| [A2, A3] | [M2,M4] |
+--------------+---------+
Code:
Then the following code creates the above mentioned inverted map in 4th step.
Map<List<Integer>, List<String>> invertedMap = inputMap.entrySet().stream()
.flatMap(test::getAllCombinationsOfAList)
.collect(Collectors.groupingBy(Entry::getKey,
Collectors.mapping(Entry::getValue, Collectors.toList())));
where test::getAllCombinationsOfAList
is(with max 2^list_len iterations):
static Stream<Entry<ArrayList<Integer>, String>> getAllCombinationsOfAList(Entry<String,List<Integer>> set)
{
int n = set.getValue().size();
Builder<Entry<ArrayList<Integer>,String>> entryStream = Stream.builder();
for (int i = 0; i < (1<<n); i++)
{
ArrayList<Integer> integers = new ArrayList<>();
for (int j = 0; j < n; j++) {
if ((i & (1 << j)) > 0)
integers.add(set.getValue().get(j));
}
if(integers.size() >=2 ) {
entryStream.accept(new AbstractMap.SimpleEntry<>(integers,set.getKey()));
}
}
return entryStream.build();
}
Then the output of res.entrySet().forEach(System.out::println);
is:
[1, 2, 3]=[M2]
[2, 3]=[M2, M4]
[1, 2]=[M2, M3]
[1, 3]=[M1, M2]
Here, key_list_length
represents the min number of elements which should be common for matching.
value_list_length
>=2 represents that there is indeed a matching.
So a key_list_length >= 2
& a value_list_length >= 2
would be the desired output for you. eg:
Map<List<Integer>, List<String>> filteredMap = invertedMap.entrySet()
.stream()
.filter(e -> e.getKey().size() >=2 && e.getValue().size() >= 2)
.collect(Collectors.toMap(Entry::getKey,Entry::getValue));
filteredMap.entrySet().forEach(System.out::println);
Output:
[1, 2]=[M2, M3]
[2, 3]=[M2, M4]
[1, 3]=[M1, M2]