Find length of array of functions in Julia - vector

I want to find the length, nc, of this "vector of functions". I should be 2.
comp(x) = [([x[5], x[6], x[7], x[8],x[9], x[10]], tmp(x)) ; ([x[1],x[2]], [x[3],x[4]])];
nc = ....
I tried with length(comp) and length(comp(x)) but it doesn't work. I get "x not defined" and "no method matching length(::typeof(comp))", respectively.

Pulling together some of the comments to hopefully make things clearer:
What you have written is essentially
function comp(x)
a = [x[5], x[6], x[7], x[8],x[9], x[10]]
b = [x[1],x[2]]
c = [x[3],x[4]]
return [(a, tmp(x)); (b, c)]
end
that is, you have defined a function comp which takes one argument x and then returns a 2-element vector of 2-element tuples, with the first tuple holding values 5 to 10 of x and the result of tmp(x) (this function is not defined in your code so we don't know what it returns), and the second tuple holding the first and second, and third and fourth elements of x, respectively.
To illustrate, assume tmp(x) just sums up the elements of x, then we can pass some array (in the below example a range) of numbers to comp and see it in action:
julia> tmp(x) = sum(x)
tmp (generic function with 1 method)
julia> comp(1:20)
2-element Vector{Tuple{Vector{Int64}, Any}}:
([5, 6, 7, 8, 9, 10], 210)
([1, 2], [3, 4])
and you can get the result of the return value:
julia> length(comp(1:20))
2

Related

How to append to an empty list in Julia?

I want to create an empty lsit and gardually fill that out with tuples. I've tried the following and each returns an error. My question is: how to append or add and element to an empty array?
My try:
A = []
A.append((2,5)) # return Error type Array has no field append
append(A, (2,5)) # ERROR: UndefVarError: append not defined
B = Vector{Tuple{String, String}}
# same error occues
You do not actually want to append, you want to push elements into your vector. To do that use the function push! (the trailing ! indicates that the function modifies one of its input arguments. It's a naming convention only, the ! doesn't do anything).
I would also recommend creating a typed vector instead of A = [], which is a Vector{Any} with poor performance.
julia> A = Tuple{Int, Int}[]
Tuple{Int64, Int64}[]
julia> push!(A, (2,3))
1-element Vector{Tuple{Int64, Int64}}:
(2, 3)
julia> push!(A, (11,3))
2-element Vector{Tuple{Int64, Int64}}:
(2, 3)
(11, 3)
For the vector of string tuples, do this:
julia> B = Tuple{String, String}[]
Tuple{String, String}[]
julia> push!(B, ("hi", "bye"))
1-element Vector{Tuple{String, String}}:
("hi", "bye")
This line in your code is wrong, btw:
B = Vector{Tuple{String, String}}
It does not create a vector, but a type variable. To create an instance you can write e.g. one of these:
B = Tuple{String, String}[]
B = Vector{Tuple{String,String}}() # <- parens necessary to construct an instance
It can also be convenient to use the NTuple notation:
julia> NTuple{2, String} === Tuple{String, String}
true
julia> NTuple{3, String} === Tuple{String, String, String}
true

How to count minimum on multiple variables in Julia

I want to plot correct y-axis limits. So, require to count the maximum y and minimum y.
y1=[2 3 4]
y2=[7 5 6]
...
m = minimum(y1)
m = minimum(m, minimum(y2))
error message
ERROR: MethodError: objects of type Int64 are not callable
Maybe you forgot to use an operator such as *, ^, %, / etc. ?
Stacktrace:
[1] mapreduce_first(f::Int64, op::Function, x::Int64)
# Base ./reduce.jl:419
[2] mapreduce(f::Int64, op::Function, a::Int64)
# Base ./reduce.jl:446
[3] minimum(f::Int64, a::Int64; kw::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
# Base ./reduce.jl:725
[4] minimum(f::Int64, a::Int64)
# Base ./reduce.jl:725
[5] top-level scope
# REPL[107]:1
Previous code is just a simplified code, in my case, it require parse and get from a loop the pseudo code like:
x_data, y_data, names, y_min, y_max = [], [], [], 100, 0
for filename in *.csv
df = parse_csv(filename) # df is a dataframe
push!(names, filename)
d = df.value
y_min = minimum(y_min, d)
....
end
# plot all file by the y_min, y_max
i=1
for d in y_data;
lineplot(x_data, d, ylims=(y_min,y_max), name=names[i])
i += 1
end
Here are two solutions:
First. This is simple, just take the minimums of the minimums, etc.
julia> min(minimum(y1), minimum(y2))
2
julia> max(maximum(y1), maximum(y2))
7
Second solution. This iterates over each pair of values from y1 and y2, takes the minimum/maximum of each pair, and then finds the minimum of those again.
julia> minimum(minimum, zip(y1, y2))
2
julia> maximum(maximum, zip(y1, y2))
7
Here's a third one:
julia> min(y1..., y2...)
2
julia> max(y1..., y2...)
7
Elegant, but splatting of vectors is often inefficient in terms of performance.
The problem is that you don't know the difference between the min function and the minimum function (or you're unaware of the min function):
minimum(itr; [init])
Returns the smallest element in a collection.
So it gets a collection (E.g., Array) and returns the minimum of it.
min(x, y, ...)
Return the minimum of the arguments.
This one gets indefinite arguments and returns the minimum of them! It can't apply min on the x if the x is a container by itself!
julia> min(2, 3)
2
julia> min([2, 3])
ERROR: MethodError: no method matching min(::Vector{Int64})
On the other hand, for the minimum function:
julia> minimum(2, 3)
ERROR: MethodError: objects of type Int64 are not callable
julia> minimum([2, 3])
2
So I wanted to explain these to you to understand your code's meaning better.
We have this minimum(m, minimum(y2)) expression in your code block. This is literally the same as minimum(2, 5). So you're not passing containers to the function, leading to an error! For this, you should choose min instead:
julia> m = min(m, minimum(y2))
2
Or we can wrap m and minimum(y2) in a container and use the minimum function to achieve the overall min:
julia> m = minimum([m, minimum(y2)])
2
If you follow the explanation, you can absolutely understand the following:
julia> min(m, minimum(y2)) == minimum([m, minimum(y2)]) == min(m, min(y2...))
true

How to delete an element from a list in Julia?

v = range(1e10, -1e10, step=-1e8) # velocities [cm/s]
deleteat!(v, findall(x->x==0,v))
I want to delete the value 0 from v. Following this tutorial, I tried deleteat! but I get the error
MethodError: no method matching deleteat!(::StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, ::Vector{Int64})
What am I missing here?
Notice the type that is returned by the function range.
typeof(range(1e10, -1e10, step=-1e8))
The above yields to
StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
Calling the help function for the function deleteat!.
? deleteat!()
deleteat!(a::Vector, inds)
Remove the items at the indices given by inds, and return the > modified a. Subsequent items are shifted to fill the resulting gap.
inds can be either an iterator or a collection of sorted and > unique integer indices, or a boolean vector of the same length as a with true indicating entries to delete.
We can convert the returned type of range using collect. Try the following code.
v = collect(range(1e10, -1e10, step=-1e8))
deleteat!(v,findall(x->x==0,v))
Notice that we can shorten x->x==0 to iszero which yields to
v = collect(range(1e10, -1e10, step=-1e8))
deleteat!(v,findall(iszero,v))
Use filter! or filter:
julia> filter!(!=(0), [1,0,2,0,4])
3-element Vector{Int64}:
1
2
4
In case of a range you can collect it or use:
julia> filter(!=(0), range(2, -2, step=-1))
4-element Vector{Int64}:
2
1
-1
-2
However for big ranges you might just not want to materialize them to save the memory footprint. In that case you could use:
(x for x in range(2, -2, step=-1) if x !== 0)
To see what is being generated you need to collect it:
julia> collect(x for x in range(2, -2, step=-1) if x !== 0)
4-element Vector{Int64}:
2
1
-1
-2

How to add missing and value in Julia and get the value instead of missing

Is it possible with the new version of Julia (1.3.0) to add "missing" + 1 and get a "1" instead of a "missing"?? I want to sum two columns from an Array and skip the missings, but keeping the same number of rows. Thanks!
This is a somewhat unusual treatment of missing - if I understand you correctly you want missing to behave like a zero if added to another number, and like missing when added to another missing. Given that this is a bit unusual, I would just write it out explicitly:
julia> a = [1, missing, missing]; b = [2, 1, missing];
julia> ifelse.(ismissing.(a) .& ismissing.(b), missing, coalesce.(a, 0) .+ coalesce.(b, 0))
3-element Vector{Union{Missing, Int64}}:
3
1
missing
coalesce replaces missing with 0 in the above, but the result of that addition is only used if either of the two values being added is nonmissing.
Given your requirements I would recommend you to define your own custom addition that would implement the rule you want:
julia> ⨨(::Missing, ::Missing) = missing
⨨ (generic function with 1 method)
julia> ⨨(x, ::Missing) = x
⨨ (generic function with 2 methods)
julia> ⨨(::Missing, x) = x
⨨ (generic function with 3 methods)
julia> ⨨(x, y) = x + y
⨨ (generic function with 4 methods)
julia> [1, 2, missing, missing] .⨨ [10, missing, 30, missing]
4-element Vector{Union{Missing, Int64}}:
11
2
30
missing
In my example ⨨ can be typed by \plustrif<tab> (you could use any other symbol that is accepted as operator instead).
This is the most efficient way to achieve what you want.

Understand Function capturing through map and reduce

I 'am beginner in Elixir language , so In the blow example
iex> Enum.reduce([1, 2, 3], 0, &+/2)
6
iex> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]
In the reduce method I understand that we capture the second arg and we add to it the list values until we reach the end of the List .
but in the map method I can't understand how the capturing works?
reference
http://elixir-lang.org/getting-started/recursion.html
map/2 and reduce/2 are two different functions.
map/2 takes some values and a function that takes a single value and applies that function to each element in the collection, effectively transforming it into a list.
reduce/2 takes some values and a function that takes 2 arguments. The first argument of that function is the element in your collection, while the second is an accumulator. So the function reduces your collection down to a single value.
Using the syntax &+/2, this does not capture the second argument. It calls the + function on the two arguments. The /2 is to denote that it has an arity of 2 (it takes 2 arguments). Take the following code as an example.
iex(1)> fun = &+/2
&:erlang.+/2
iex(2)> fun.(1,2)
3
Here, we set the + function to the variable fun. We can then apply that function to our arguments in order to get a value.
The other syntax &(&1 * 2) creates an anonymous function that takes our one and only argument (represented by &1) and multiplies it by 2. The initial & just means that it is an anonymous function.
iex(3)> fun2 = &(&1 * 2)
#Function<6.118419387/1 in :erl_eval.expr/5>
iex(4)> fun2.(5)
10
They are similar concepts, but slightly different.
Basically:
map returns you new list as a result of applying function on each element of the list
reduce returns you result of the computation of applied function over the list - you reduced the whole collection into (most likely) one result eg. integer
In your example:
iex> Enum.reduce([1, 2, 3], 0, &+/2)
# it equals:
0 + 1 # first step, 1 is out of the list now
1 + 2 # second step, 2 is out of the list now
3 + 3 # last step, 3 is out of the list now, return 6
iex> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]
# apply for each element function fn(x) -> 2 * x end, but with syntactic sugar
There are three different ways to express an anonymous function, when passing it as an argument:
Enum.reduce([1, 2, 3], 0, fn p1, p2 -> p1 + p2 end)
or, using a shorthand and enumerated params:
Enum.reduce([1, 2, 3], 0, &(&1 + &2))
or, explicitly naming the function of the respective arity (2 for reduce, because reduce expects a function of arity 2):
Enum.reduce([1, 2, 3], 0, &+/2)
The latter, while looking cumbersome, is just a common way to write a function name with it’s arity. Kernel.+/2 is a function name here. If you were using your own function as the reducer:
defmodule My, do: def plus(p1, p2), do: p1 + p2
Enum.reduce([1, 2, 3], 0, &My.plus/2)
All three ways described above are 100% equivalent.
JIC: For the mapper those three ways would be:
Enum.map([1, 2, 3], fn p -> p * 2 end)
Enum.map([1, 2, 3], &(&1 * 2))
—
The third notation is not available here, since there is no such a function, that takes a number and returns it’s doubled value. But one might declare her own:
defmodule Arith, do: def dbl(p1), do: p1 * 2
Enum.map([1, 2, 3], &Arith.dbl/1) # map expects arity 1
#⇒ [2, 4, 6]

Resources