Given the following 2D numpy array M, form two sets and arrays A and B containing elements of M such that set A and set B hold no element in common. In other words, split M into two sets of rows from M, such that they span disjoint sets of numbers. The algorithm should work for any number of sets.
Given:
import numpy as np
M =
[[ 2 1 0]
[ 0 3 2]
[ 1 4 0]
[ 0 4 3]
[ 5 1 2]
[ 3 5 2]
[ 5 4 1]
[ 4 5 3]
[ 8 7 6]
[ 6 9 8]
[ 7 10 6]
[ 6 10 9]
[11 7 8]
[ 9 11 8]
[11 10 7]
[10 11 9]]
Return:
setA = {0, 1, 2, 3, 4, 5}
setB = {6, 7, 8, 9, 10, 11}
A =
[[ 2 1 0]
[ 0 3 2]
[ 1 4 0]
[ 0 4 3]
[ 5 1 2]
[ 3 5 2]
[ 5 4 1]
[ 4 5 3]]
B =
[[ 8 7 6]
[ 6 9 8]
[ 7 10 6]
[ 6 10 9]
[11 7 8]
[ 9 11 8]
[11 10 7]
[10 11 9]]
I was able to form both matrices A and B (the sets aren't strictly necessary), but my code seems inelegant and I wonder if there is a better way. I also have the feeling it might fail if the elements of M come out of order.
Edit: Correction: My code works for this example, but not for others.
My solution:
objects = []
obj = []
i = 0
for idx, face in enumerate(M):
if i == 0:
obj.append(face)
i = i + 1
else:
if np.isin(face,obj).any():
obj.append(face)
else:
objects.append(obj.copy())
obj = []
obj.append(face)
i = 0
if idx == len(M)-1:
objects.append(obj.copy())
print(np.array(objects[0]),'\n\n',np.array(objects[1]))
# returns
[[2 1 0]
[0 3 2]
[1 4 0]
[0 4 3]
[5 1 2]
[3 5 2]
[5 4 1]
[4 5 3]]
[[ 8 7 6]
[ 6 9 8]
[ 7 10 6]
[ 6 10 9]
[11 7 8]
[ 9 11 8]
[11 10 7]
[10 11 9]]
Note: I tag networkx because I am curious if there is a solution through it. I've used it elsewhere in my code and it has sped everything up enormously.
If curious:
This relates to a problem I've been puzzling over. Each element in M represents a triangular face
, where each element of the face
is a vertex of the triangle. In M, there are two full objects. A and B are unconnected. The above algorithm is a way of sorting M for objects A and B.