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