Bosnia
Bosnia

Reputation: 333

Matlab: How to assign values selectively to a matrix

I have 3 matrices x, y and z of order 3*3. I want to create a new matrix k with value = 1./(x.^2+y.^2+z.^2) if (x.^2+y.^2+z.^2 > 1) and value = 0 otherwise. I am trying to use this :

  k(x.^2+y.^2+z.^2>1)= 1./(x.^2+y.^2+z.^2)

but it gives error : In an assignment A(I) = B, the number of elements in B and I must be the same. Can anyone provide a simple solution in a single line where I don't need to use for loops

Upvotes: 2

Views: 193

Answers (3)

Ben Voigt
Ben Voigt

Reputation: 283684

How about

k = x.^2+y.^2+z.^2;
k(k < 1) = 0;
k(k~= 0) = 1 ./ k(k~=0);

Upvotes: 0

Alex Lizz
Alex Lizz

Reputation: 445

If you are trying to save some processing time (i.e. do not compute at all the sum of squares for those cases when it is less than one) then pretty much the only solution is a table lookup Otherwise the following code should work

k=1./(x.^2+y.^2+z.^2)
k(k<=1)=0

you can cut some time (assuming x, y and z could be greater than 1)

idx0=x<1 & y<1 & z<1
k=zeros(3)
k(idx0)=1./(x(idx0).^2+y(idx0).^2+z(idx0)^2)
k(k<=1)=0

Your original solution will work if you change it to use an indexer (I haven't profiled it, but I am pretty sure it will take longer, than mine :) )

idx0=x.^2+y.^2+z.^2>1
k=zeros(3)
k(idx0)=1./(x(idx0).^2+y(idx0).^2+z(idx0)^2)

Upvotes: -1

Nitish
Nitish

Reputation: 7156

I am not sure why you'd want to do this as opposed to splitting it up into two operations. This way, you save the cost of computing the sum of squares twice.

x = rand(3,3);
y = rand(3,3);
z = rand(3,3);
k = 1./(x.^2+y.^2+z.^2);
k(k>1)=0;

In any case, another way to do it would be using principles of Functional Programming:

x = rand(3,3);
y = rand(3,3);
z = rand(3,3);
myfun = @(x,y,z) 1/(x^2+y^2+z^2) * (x^2+y^2+z^2>1);
k = arrayfun(myfun, x, y, z);

Alternately, you can mix everything into one line as:

k = arrayfun(@(x,y,z) 1/(x^2+y^2+z^2) * (x^2+y^2+z^2>1), x, y, z);

What this code does is maps the function myfun to each of the data elements. The function myfun is quite simple. It computes the required quantity but multiplies it with the binding condition. However, you might want to beware.


EDIT: To address the comment. If you don't want to compute the quantity at all, we can use conditional anonymous functions. For more details, you can refer to this guide.

iif = @(varargin) varargin{2 * find([varargin{1:2:end}], 1, 'first')}();
myfun = @(x,y,z) iif( x^2+y^2+z^2 <= 1, @() 0, x^2+y^2+z^2>1 ,@() 1/(x^2+y^2+z^2));
k = arrayfun(myfun, x, y, z);

Upvotes: 2

Related Questions