Function loop that deals with vectors and single numbers. setindex! when i==1

Hi,
Simple question I am sure someone can answer. Looked through the help and couldn’t see an obvious example.


##Define these two functions in the REPL:

function TestFunc(X,Pa)
#TestFunc = Moves a point by movement set in Pa
#X - 	Point to move
#Pa - 	Movement

for i=1:length(X) 
	#Centre object 'XYZ' relative to point Pa
	X[i] =  X[i]-Pa;
end
return(X)

end

function TestFunc2(X,Pa)
#TestFunc2 = Moves a point by movement set in Pa
#X - 	Point to move
#Pa - 	Movement

if length(X)==1 #Catch error if X is not an array
	X =  X-Pa;
else
	for i=1:length(X) #And if it is an array do for every point 
		#Centre object 'XYZ' relative to point PaPbPc
		X[i] =  X[i]-Pa;
	end
end

return(X)

##Now define inputs

X=1.0;
Pa=-1.0;

TestFunc(X,Pa);
TestFunc2(X,Pa);

##If I use:

X=[1.0 1.0];
Pa=-1.0;

TestFunc(X,Pa);
TestFunc2(X,Pa);

##It works fine

For TestFunc we get:
ERROR: MethodError: no method matching setindex!(::Float64, ::Float64, ::Int64)
Stacktrace:
[1] TestFunc(::Float64, ::Float64) at C:\Users\timmm.julia\MyPackage\src\TestFunc.jl:8
[2] top-level scope at none:0

Do I need to include the catch I have added to TestFunc2 if I want to allow my functions to deal with single arrays and vectors? Is this the best way of doing it?

Cheers,
Tim

Please quote your code.

2 Likes

You can use broadcasting,

X .- a

Those functions seem to indicate you want an in-place function (e.g., TestFunc!). Containers can be mutable such as arrays (e.g., Vector{<:Real}), but Int, Float64 and such are immutable. I would recommend either always use a mutable struct and update in-place or just return the latest value.

A few suggestions,

  1. Instead of 1:length(obj) use eachindex(obj)
  2. Instead of a for loop, use broadcast, X .-= Pa
  3. To test whether X is an array use isa(X, AbstractArray) or
    isa(X, AbstractVector); opposite would be X isa Number or such.

Don’t test for types explicitly, use multiple dispatch instead, ie define different methods accepting vectors and scalars.

2 Likes

If not mistaken for a simple branch that only depends on type there is not efficiency loss as the compiler will be smart about it, same as multiple dispatch.

In this case, it is probably best to choose an in-place for a mutable container or avoid it and return the value (e.g., just defining the operation on a scalar and broadcasting). In the off-chance that it needs both methods, then multiple dispatch would be appropriate.

done, sorry

Thanks for replies, useful comments.