I would like to detect rows in a matrix which only occur once, also the column order does not matter. This relates to this discussion.
I have implemented several options (see below), and all work (note though I am a Julia novice so they might look silly), except they do not scale up well. They quickly become very slow. For instance occursOnce4 below takes 75 seconds for a (200406, 4) array on my machine:
I have also checked the counter function as part of DataStructures. That seems fast. However it produces counts on a unique set, which in this case is Fs, i.e. the column direction sorted version of my input. So I cannot use the counts without the accompanying unique row set (unsorted). Also functions like counter, and also unique unfortunately do not export the indices for the unique members.
Any help would be appreciated. Thanks!
Here is an example mini matrix:
F=[1 2 3 4; 5 6 7 8; 4 3 2 1; 7 8 6 5; 1 2 5 6; 8 7 6 5; 5 6 7 8]
and more complex examples can be created using something like:
F=repeat(rand(1:500,5,4),3,1)
For background I am parsing 4 noded quadrilateral face arrays and am looking for faces that are not doubled, i.e. the boundary faces of a volumetric hexahedral mesh.
function occursOnce1(F)
Fs=sort(F,dims=2)
S=prod(string.(Fs),dims=2)
L=zeros(Bool,size(F,1))
for q=1:1:size(F,1)#Loop over faces
L[q]=count(S.==S[q])==1
end
return L
end
function occursOnce2(F)
Fs=sort(F,dims=2)
L=zeros(Bool,size(F,1))
for q=1:1:size(F,1)#Loop over faces
L[q]=count([Fs[q,:]==Fs[i,:] for i=1:1:size(F,1)])==1
end
return L
end
function occursOnce3(F)
Fs=sort(F,dims=2) #Sorted across columns
L=zeros(Bool,size(F,1)) #Initialize boolean array
for q=1:1:size(F,1) #Loop over faces
L[q]=count(Fs[q,1].==Fs[:,1] .&& Fs[q,2].==Fs[:,2] .&& Fs[q,3].==Fs[:,3] .&& Fs[q,4].==Fs[:,4]) ==1 #Check count
end
return L
end
function occursOnce4(F)
Fs=sort(F,dims=2)
L=[count(==(r),eachrow(Fs)) for r in eachrow(Fs)].==1
return L
end