How to delete an element from a list in Julia? - 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

Related

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

Compare array values with a value in Julia

I have an array a = [1, 2, 3, 4];. I want to compare each element of array a with a number and return a new array contains True/False elements in Julia as few steps as possible. I try result = a < 2 and expected array is result = [True, False, False, False] but it's not working. Hope your help
You need to vectorize (broadcast) the comparison operator so it operates on Vectors.
You can do this by adding a dot . to your code.
julia> a = [1, 2, 3, 4]
4-element Vector{Int64}:
1
2
3
4
julia> a .<= 2
4-element BitVector:
1
1
0
0
Read more about broadcasting here.
Note that Python's numpy will do this for you automatically, but there are cases where an operation might be ambiguous - do you want it to be element wise or a matrix multiplication? So Julia solves this by explicitly broadcasting any operation with the . command.

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.

Find indices of non-zero elements from [1,2,0,0,4,0] in julia and create an Arrray with them

I know there is a function that does this, for example:
A = [1,2,0,0,4,0]
find(A)
3-element Array{Int64,1}:
1
2
5
I am trying to do it on my own way, however, I am stuck here
for i=1:endof(A)
if A[i] != 0
[]
end
end
Thanks in advance.
Here's one alternative:
function myfind(c)
a = similar(c, Int)
count = 1
#inbounds for i in eachindex(c)
a[count] = i
count += (c[i] != zero(eltype(c)))
end
return resize!(a, count-1)
end
It actually outperformed find for all the cases I tested, though for the very small example vector you posted, the difference was negligible. There is perhaps some performance advantage to avoiding the branch and dynamically growing the index array.
I have notice that the question is really confusion (because is poorly formulated, sorry about that). Therefore, there are two possible answers: one is [1,2,4]which is an array with the non-zero elements; the other is [1,2,5] which is an array of the indices of the non-zero elements.
Let´s begin with the first option
A = [1,2,0,0,4,0]
B = []
for i=1:endof(A)
if A[i] != 0
push!(B,i)
end
end
println(B)
The output is Any[1,2,5]
However, the type is not the one I wanted. Using typeof(B) it shows Array{Any,1} so I added this code:
B = Array{Int64}(B)
println(B)
typeof(B)
And the result is the desired
[1,2,5]
Array{Int64,1}
To improve its efficiency, following with the recommendations in the comments, I have specified the type of B with the eltype() function before the loop as follows:
A1 = [1,2,0,0,4,0] #The default type is Array{Int64,1}
B1 = eltype(A1)[] #Define the type of the 0 element array B with the type of A
#B1 = eltype(typeof(A))[] this is also valid
for i=1:endof(A1)
if A1[i] != 0
push!(B1::Array{Int64,1},i::Int64)
end
end
println(B1)
typeof(B1)
Then, the output is again the desired
[1,2,5]
Array{Int64,1}
The simplest way of doing this is using the function find(). However, since I´m a beginner, I wanted to do it in another way. However, there is another alternative provided by #DNF that outperform find() for the cases he has tested it (see below answers).
The second option, which creates an output matrix with the non-zero elements has been provided by other users (#Harrison Grodin and #P i) in this discussion.
Thanks all of you for the help!
You have a few options here.
Using the strategy you started with, you can use push! inside the for loop.
julia> B = Int[]
0-element Array{Int64,1}
julia> for element = A
if element != 0
push!(B, element)
end
end
julia> B
3-element Array{Int64,1}:
1
2
4
You can also opt to use short-circuit evaluation.
julia> for element = A
element != 0 && push!(B, element)
end
julia> for element = A
element == 0 || push!(B, element)
end
Both filter and list comprehensions are valid, as well!
julia> B = [element for element = A if element != 0]
3-element Array{Int64,1}:
1
2
4
julia> filter(n -> n != 0, A)
3-element Array{Int64,1}:
1
2
4
Edit: Thanks to the OP's comment, I have realized that the desired result is the indices of the nonzero elements, not the elements themselves. This can be achieved simply with the following. :)
julia> find(A)
3-element Array{Int64,1}:
1
2
5
Just because I don't see a simple solution posted here, this is approach I took to the same problem. I think it is the simplest and most elegant solution. Hope this closes the thread!
julia> A = [1,2,0,0,4,0];
julia> findall(!iszero,A)
3-element Vector{Int64}:
1
2
5

Re. partitions()

Why is
julia> collect(partitions(1,2))
0-element Array{Any,1}
returned instead of
2-element Array{Any,1}:
[0,1]
[1,0]
and do I really have to
x = collect(partitions(n,m));
y = Array(Int64,length(x),length(x[1]));
for i in 1:length(x)
for j in 1:length(x[1])
y[i,j] = x[i][j];
end
end
to convert the result to a two-dimensional array?
From the wikipedia:
In number theory and combinatorics, a partition of a positive integer n, also called an integer partition, is a way of writing n as a sum of positive integers.
For array conversion, try:
julia> x = collect(partitions(5,3))
2-element Array{Any,1}:
[3,1,1]
[2,2,1]
or
julia> x = partitions(5,3)
Base.FixedPartitions(5,3)
then
julia> hcat(x...)
3x2 Array{Int64,2}:
3 2
1 2
1 1
Here's another approach to your problem that I think is a little simpler, using the Combinatorics.jl library:
multisets(n, k) = map(A -> [sum(A .== i) for i in 1:n],
with_replacement_combinations(1:n, k))
This allocates a bunch of memory, but I think your current approach does too. Maybe it would be useful to make a first-class version and add it to Combinatorics.jl.
Examples:
julia> multisets(2, 1)
2-element Array{Array{Int64,1},1}:
[1,0]
[0,1]
julia> multisets(3, 5)
21-element Array{Array{Int64,1},1}:
[5,0,0]
[4,1,0]
[4,0,1]
[3,2,0]
[3,1,1]
[3,0,2]
[2,3,0]
[2,2,1]
[2,1,2]
[2,0,3]
⋮
[1,2,2]
[1,1,3]
[1,0,4]
[0,5,0]
[0,4,1]
[0,3,2]
[0,2,3]
[0,1,4]
[0,0,5]
The argument order is backwards from yours to match mathematical convention. If you prefer the other way, that can easily be changed.
one robust solution can be achieved using lexicographic premutations generation algorithm, originally By Donald Knuth plus classic partitions(n).
that is lexicographic premutations generator:
function lpremutations{T}(a::T)
b=Vector{T}()
sort!(a)
n=length(a)
while(true)
push!(b,copy(a))
j=n-1
while(a[j]>=a[j+1])
j-=1
j==0 && return(b)
end
l=n
while(a[j]>=a[l])
l-=1
end
tmp=a[l]
a[l]=a[j]
a[j]=tmp
k=j+1
l=n
while(k<l)
tmp=a[k]
a[k]=a[l]
a[l]=tmp
k+=1
l-=1
end
end
end
The above algorithm will generates all possible unique
combinations of an array elements with repetition:
julia> lpremutations([2,2,0])
3-element Array{Array{Int64,1},1}:
[0,2,2]
[2,0,2]
[2,2,0]
Then we will generate all integer arrays that sum to n using partitions(n) (forget the length of desired arrays m), and resize them to the lenght m using resize_!
function resize_!(x,m)
[x;zeros(Int,m-length(x))]
end
And main function looks like:
function lpartitions(n,m)
result=[]
for i in partitions(n)
append!(result,lpremutations(resize_!(i, m)))
end
result
end
Check it
julia> lpartitions(3,4)
20-element Array{Any,1}:
[0,0,0,3]
[0,0,3,0]
[0,3,0,0]
[3,0,0,0]
[0,0,1,2]
[0,0,2,1]
[0,1,0,2]
[0,1,2,0]
[0,2,0,1]
[0,2,1,0]
[1,0,0,2]
[1,0,2,0]
[1,2,0,0]
[2,0,0,1]
[2,0,1,0]
[2,1,0,0]
[0,1,1,1]
[1,0,1,1]
[1,1,0,1]
[1,1,1,0]
The MATLAB script from http://www.mathworks.com/matlabcentral/fileexchange/28340-nsumk actually behaves the way I need, and is what I though that partitions() would do from the description given. The Julia version is
# k - sum, n - number of non-negative integers
function nsumk(k,n)
m = binomial(k+n-1,n-1);
d1 = zeros(Int16,m,1);
d2 = collect(combinations(collect((1:(k+n-1))),n-1));
d2 = convert(Array{Int16,2},hcat(d2...)');
d3 = ones(Int16,m,1)*(k+n);
dividers = [d1 d2 d3];
return diff(dividers,2)-1;
end
julia> nsumk(3,2)
4x2 Array{Int16,2}:
0 3
1 2
2 1
3 0
using daycaster's lovely hcat(x...) tidbit :)
I still wish there would be a more compact way of doing this.
The the first mention of this approach seem to be https://au.mathworks.com/matlabcentral/newsreader/view_thread/52610, and as far as I can understand it is based on the "stars and bars" method https://en.wikipedia.org/wiki/Stars_and_bars_(combinatorics)

Resources