# Modifying a list of matrices with conditional statement

I have a list of around 100 matrices, that looks like this

A={{{425060., 2.14235*10^6, 0.49, 0.01, 0.38, 0.620161,
20.}, {1.24808*10^6, 1.53025*10^6, 0.04, 0.07, 0.31, 0.320312,
20.}, {7.39304*10^6, 1.40204*10^6, 0.83, 0.45, 0.09, 0.94842, 20.} .... {4.27537*10^6,
1.62124*10^6, 0.24, 0.28, 0.62, 0.721388, 20.1}, {3.27776*10^6,
2.25816*10^6, 0.01, 0.21, 0.72, 0.750067, 20.1}, {3.0814*10^6,
1.95624*10^6, 0.02, 0.19, 0.72, 0.744916, 20.1}, {2.42706*10^6,
1.25729*10^6, 0.03, 0.17, 0.7, 0.720972, 20.1}, {4.47196*10^6,
1.23247*10^6, 0.24, 0.27, 0.57, 0.674833, 20.1}, {1.57132*10^7,
1.65019*10^6, 0.76, 0.92, 0.5, 1.29383, 20.1} ......


Each matrix has an unknown number of rows. Each matrix holds information about a group of particles at a given time. Columns 3,4,5 are the x,y and z coordinate of each particle. For each matrix, I want to compare the Euclidean distance between every two particles, and keep the particle whose distance from all other particles in that matrix is greater than 0.01. I want to use the following algorithm, I pick a matrix, then pick its first row, then I check whether EuclideanDistance[{#3, #4, #5}, {from all other particles}]> 0.01 then that row (that particle) gets copied into another matrix, if not, then ignore both the elements for further computation. This way a new list of matrix will be created with particles which are at least 0.01 units away from each other.

EDIT : I am getting error messages EuclideanDistance::argr: EuclideanDistance called with 1 argument; 2 arguments are expected. >> Pick::incomp: Expressions {{1.13266*10^7,1.40618*10^6,0.82,0.67,0.35,1.11526,22.7}} and {EuclideanDistance[{0.82,0.67,0.35}]>0.01} have incompatible shapes. >> EuclideanDistance::argr: EuclideanDistance called with 1 argument; 2 arguments are expected. >> Pick::incomp: Expressions {{1.13266*10^7,1.38136*10^6,0.82,0.67,0.35,1.11526,22.8}} and {EuclideanDistance[{0.82,0.67,0.35}]>0.01} have incompatible shapes

this is happening when there is only one element in the matrix, as EuclideanDistance requires two arguments. Is there any way I can have the Euclidean distance skip over these single elements, yet the fina list of matrices will have those single elements?

Taking one the matrices out of your 100, say

aA = {{4.27537*10^6, 1.62124*10^6, 0.24, 0.28, 0.62, 0.721388, 20.1},
{3.27776*10^6, 2.25816*10^6, 0.01, 0.21, 0.72, 0.750067, 20.1},
{3.0814*10^6, 1.95624*10^6, 0.02, 0.19, 0.72, 0.744916,  20.1},
{2.42706*10^6, 1.25729*10^6, 0.03, 0.17, 0.7, 0.720972,  20.1},
{4.47196*10^6, 1.23247*10^6, 0.24, 0.27, 0.57, 0.674833, 20.1},
{1.57132*10^7, 1.65019*10^6, 0.76, 0.92, 0.5, 1.29383,   20.1}};


Create a Nearest function for the matrix based on columns {3,4,5}:

nf = Nearest[aA[[All, {3, 4, 5}]]];


so that

nf[u, 2]


gives the two elements that are closest to u; one of the those two is, of course, u.

Then, for a threshold distance t

Pick[aA, EuclideanDistance @@ nf[#, 2] > t & /@ aA[[All, {3, 4, 5}]]]


picks the elements of the matrix whose {x,y,z} coordinates are at least t distance far from the {x,y,z} coordinates of the other elements.

t = .03;
Pick[aA, EuclideanDistance @@ nf[#, 2] > t & /@ aA[[All, {3, 4, 5}]]]


{{4.27537*10^6, 1.62124*10^6, 0.24, 0.28, 0.62, 0.721388, 20.1}, {4.47196*10^6, 1.23247*10^6, 0.24, 0.27, 0.57, 0.674833, 20.1}, {1.57132*10^7, 1.65019*10^6, 0.76, 0.92, 0.5, 1.29383, 20.1}}

Note: You could also use

Select[aA, (EuclideanDistance @@ nf[#[[{3, 4, 5}]], 2] > t) &]
(* same output *)


Update: a function that can be Mapped to the entire list of matrices:

ClearAll[pF];
pF[t_] := With[{nfunc = Nearest[#[[All, {3, 4, 5}]]], mat = #},
Pick[mat, EuclideanDistance @@ nfunc[#, 2] > t & /@ mat[[All, {3, 4, 5}]]]] &;


Example:

pF[.03] @ aA
(* same result as above *)

aB = {{425060., 2.14235*10^6, 0.49, 0.01, 0.38, 0.620161, 20.},
{1.24808*10^6, 1.53025*10^6, 0.04, 0.07, 0.31, 0.320312, 20.},
{7.39304*10^6, 1.40204*10^6, 0.83, 0.45, 0.09, 0.94842,  20.}};

A={aB,aA};

result = pF[.03] /@ A;
TableForm[TableForm /@ result, TableSpacing -> 3 ]


• That is brilliant! thank you. Is there a way I can automatically do this for all the matrices in the list instead of doing it one by one? – HuShu Oct 31 '14 at 22:01
• @NilanjanBanik, thank you for the Accept. Updated with a function that can be used with a list of matrices. – kglr Oct 31 '14 at 23:28
• I am getting error messages EuclideanDistance::argr: EuclideanDistance called with 1 argument; 2 arguments are expected. >> Pick::incomp: Expressions {{1.13266*10^7,1.40618*10^6,0.82,0.67,0.35,1.11526,22.7}} and {EuclideanDistance[{0.82,0.67,0.35}]>0.01} have incompatible shapes. >> EuclideanDistance::argr: EuclideanDistance called with 1 argument; 2 arguments are expected. >> Pick::incomp: Expressions {{1.13266*10^7,1.38136*10^6,0.82,0.67,0.35,1.11526,22.8}} and {EuclideanDistance[{0.82,0.67,0.35}]>0.01} have incompatible shapes. >> – HuShu Nov 1 '14 at 1:02
• Ah I just found out why, because those matrices have only one row. – HuShu Nov 1 '14 at 1:13
• @HuShu, does it work if you use pF2 instead of pF where ClearAll[pF2]; pF2[t_] := With[{nfunc = Nearest[#[[All, {3, 4, 5}]]], mat = #}, If[Length@mat <= 1, mat, Pick[mat, EuclideanDistance @@ nfunc[#, 2] > t & /@ mat[[All, {3, 4, 5}]]]]] &;? – kglr May 2 '15 at 8:23