Julia nested loop - julia

I am trying to find the duplicate value which occours the first in a list or array. I created the below code which worked in Python and trying to replicate it in Julia, but not getting the desired result. Can you please help?
def firstDuplicateValue(array):
# Write your code here.
index = float('inf')
for x, i in enumerate(array):
for j, k in enumerate(array):
if i == k and x != j and j > x:
if j < index:
index = j
if index == float('inf'):
return -1
else:
return array[index]
I have created the same code in Julia as below but I am getting the desired result -
function firstDuplicateValue(array)
index = Inf
for (ind_1, value_1) in enumerate(array)
for (ind_2, value_2) in enumerate(array)
if value_1 == value_2 && ind_2 > ind_1
if ind_2 < index
index = ind_2
end
end
end
end
if index == Inf
return -1
else return array[index]
end
end
I know there are other optimum ways of doing it, but this is just to learn basics of Julia.
added from an answer by the OP: It worked for me, I was providing the wrong input to the function, it was a typo.

It worked for me, I was providing the wrong input to the function, it was a typo.

Related

sum function in Julia is giving error if the array is empty

I am trying to create a code which identifies if the elements in an array are monotonic or not.
I wrote the below code and got the error -
function isMonotonic(array)
if length(array) <= 2
return true
end
check_up = []
check_down = []
for i in range(2, length(array))
if array[i] <= array[i-1]
append!(check_up, 1)
end
if array[i] >= array[i - 1]
append!(check_down, 1)
end
end
if sum(check_up) == length(array) - 1 || sum(check_down) == length(array) - 1
return true
else
return false
end
end
isMonotonic([1, 2, 3, 4, 5, 6 , 7])
I am getting the below error
Error: Methoderror: no method matching zero(::Type{Any})
I think it is because I am trying to sum up the empth array, I want to understand how to overcome this problem in general, I have a solution for the above code, but in genral I want to know the reason and how to use it. I do not want to first check if the array is empty or not and then do the sum.
If you wanted to save yourself lots of effort, the simplest solution would just be:
my_ismonotonic(x) = issorted(x) || issorted(x ; rev=true)
This will return true if x is sorted either forwards, or in reverse, and false otherwise.
We could maybe make it a little more efficient using a check so we only need a single call to issorted.
function my_ismonotonic(x)
length(x) <= 2 && return true
for n = 2:length(x)
if x[n] > x[1]
return issorted(x)
elseif x[n] < x[1]
return issorted(x ; rev=true)
end
end
return true
end
# Alternatively, a neater version using findfirst
function my_ismonotonic(x)
length(x) <= 2 && return true
ii = findfirst(a -> a != x[1], x)
isnothing(ii) && return true # All elements in x are equal
if x[ii] > x[1]
return issorted(x)
else
return issorted(x ; rev=true)
end
end
The loop detects the first occurrence of an element greater than or less than the first element and then calls the appropriate issorted as soon as this occurs. If all elements in the array are equal then the loop runs over the whole array and returns true.
There are a few problems of efficiency in your approach, but the reason you are getting an actual error message is because given the input, either this expression sum(check_up) or this expression sum(check_down) will effectively result in the following call:
sum(Any[])
There is no obvious return value for this since the array could have any type, so instead you get an error. If you had used the following earlier in your function:
check_up = Int[]
check_down = Int[]
then you shouldn't have the same problem, because:
julia> sum(Int[])
0
Note also that append! is usually for appending a vector to a vector. If you just want to add a single element to a vector use push!.

In Julia, a value accessed from a matrix failed to be used as an argument in a function

First, I have a function called permeability.
# permeabiliy function
# L is short for the Lable
mu_0 = 4 * pi * 10^(-7);
mu_r_core = 50;
mu_r_air = 1;
L = Int16;
function permeability(L)
if L in 1:4
if L !== 3
return mu = mu_r_air * mu_0
else
return mu = mu_r_core * mu_0
end
else
println("null") #print output in a new line
end
end
Then, I have a matrix called domain, which is shown below,
domain
2392-element Array{Int16,1}:
1
1
3
1
...
When I called permeability(domain[3]), the output is,
L = domain[3]
permeability(L)
the output is
1.2566370614359177e-6
However, when I simply called permeability(3),
permeability(3)
the output is
6.283185307179588e-5
So, it seems that the value passed from matrix domain is just "1", but in this case, domain[3] should be 3 and the result should be the same in these 2 cases.
Can someone please tell me where I was wrong?
The problem is that your array stores Int16 while 3 is an Int64. L!==3 requires L to be of the same type as 3 ie Int64. You wanted instead L!=3. Your confusion probably comes from the fact that != is the inverse of == while !== is the inverse of ===

Julia BoundsError when deleting items of a list while iterating over it

I would like to iterate over a list and occasionally delete items of said list. Below a toy example:
function delete_item!(myarray, item)
deleteat!(myarray, findin(myarray, [item]))
end
n = 1000
myarray = [i for i = 1:n];
for a in myarray
if a%2 == 0
delete_item!(myarray, a)
end
end
However I get error:
BoundsError: attempt to access 500-element Array{Int64,1} at index [502]
How can I fix it (as efficiently as possible)?
Additional information. The above seems like a silly example, in my original problem I have a list of agents which interact. Therefore I am not sure if iterating over a copy would be the best solution. For example:
#creating my agent
mutable struct agent <: Any
id::Int
end
function delete_item!(myarray::Array{agent, 1}, item::agent)
deleteat!(myarray, findin(myarray, [item]))
end
#having my list of agents
n = 1000
myarray = agent[agent(i) for i = 1:n];
#trying to remove agents from list while having them interact
for a in myarray
#agent does stuff
if a.id%2 == 0 #if something happens remove
delete_item!(myarray, a)
end
end
Unfortunately there is no single answer to this question as most efficient approach depends on the logic of the whole model (in particular do other agents' actions depend on the fact that some entry is actually deleted from an array).
In most cases the following approach should be the simplest (I am leaving findin which is inefficient but I understand that you may have duplicates in myarray in general):
n = 1000
myarray = [i for i = 1:n];
keep = trues(n)
for (i, a) in enumerate(myarray)
keep[i] || continue # do not process an agent that is marked for deletion
if a%2 == 0 # here application logic might also need to check keep in some cases
keep[findin(myarray, [a])] = false
end
end
myarray = myarray[keep]
If for some reason you really need to delete elements of myarray in each iteration here is how you can do it:
n = 1000
myarray = [i for i = 1:n];
i = 1
while i <= length(myarray)
a = myarray[i]
if a%2 == 0
todelete = findin(myarray, [a])
i -= count(x -> x < i, todelete) # if myarray has duplicates of a you have to move the counter back
deleteat!(myarray, todelete)
else
i += 1
end
end
In general the code you give will not be very fast (e.g. if you know myarray does not contain duplicates it can be much simpler - and I guess you can).
EDIT: Here is how you can implement both versions if you know you do not have duplicates (you can simply use agent's index - observe that we can also avoid unnecessary checks):
n = 1000
myarray = [i for i = 1:n];
keep = trues(n)
for (i, a) in enumerate(myarray)
if a%2 == 0 # here application logic might also need to check keep in some cases
keep[i] = false
end
end
myarray = myarray[keep]
If for some reason you really need to delete elements of myarray in each iteration here is how you can do it:
n = 1000
myarray = [i for i = 1:n];
i = 1
while i <= length(myarray)
a = myarray[i]
if a%2 == 0
deleteat!(myarray, i)
else
i += 1
end
end

Simple recursive series in matlab

I'm trying to get the sum of the first 120 terms of a series:
a(n) = (10+a(n-1))(1.005)^n
I've tried two approaches, but I don't know which mistakes I'm making.
Approach #1:
nval = 1
mval = zeros(120,1)
for nval=1:120
if nval <= 120 %counting up from 1 to 120
if nval == 1 %modifying first term to avoid 0 index
mval(1) = (10)*(1.005)
nval = nval +1;
else
mval(nval) = (10+mval(nval-1))*(1.005)^nval; %Assigning
nval = nval +1;
end
end
end
which results in a column vector with 10.05 at the top and zeroes for the rest. If if omit the opening definition of mval as zeroes, I get the same result as
Approach #2:
a(1)=10.05; %defining first term to avoid 0 index
for n=2:120, a(n)= (10+a(n-1))*(1.005)^n; end
which results in something far too large.
(The correct value for a(120) is ~1646.99)
Edit: my mistake and apologies - my series was wrong; the (1.005)^n is NOT to the nth power, but merely 1.005. Using this, both methods work.
Thanks to one and all for answers and suggestions

What functions work with JuMPArrays?

Is there a way to make certain functions such as isinteger() work with JuMPArrays?
I am using Julia/JuMP to solve an optimization problem, and after I get the solution, I want to check if the solution is integer. So here is what I wrote:
#defVar(m, 0<= x[1:3] <= 1)
...
xstar = getValue(x)
if isinteger(xstar)
...
end
And I get an error saying isinteger() has no method matching isinteger(::JuMPArray).
Thanks
So in general you can get an underlying array from a JuMPArray by using [:], e.g.
m = Model()
#variable(m, 0 <= x[1:3] <= 1)
#variable(m, 0 <= y[1:10, 1:10] <= 1)
solve(m)
xstar = getvalue(x)[:]
ystar = getvalue(y)[:,:]
Note that the reason for this is that JuMPArrays don't have to start with index 1, so the user needs to explicitly say they want a normal Julia array before doing things.
Regardless, you shouldn't use isinteger. Solvers don't always return very precise answers, e.g. they might say x[1] = 0.999996 but they really mean it is 1. You should do something like
for i in 1:3
if getvalue(x[i]) >= 0.999
println("x[$i] is 1!")
elseif getvalue(x[i]) <= 0.001
println("x[$i] is 0!")
end
end
to make sure you don't get any false negatives. If the variable is restricted to be integer or binary, use iround, e.g.
for i in 1:3
v = iround(getvalue(x[i]))
if v == 1
println("x[$i] is 1!")
elseif v == 0
println("x[$i] is 0!")
end
end
but it looks like in this case you are just seeing if the solution is naturally 0 or 1.

Resources