I'm tying to create a one liner that filters an array against an array of values. Meaning that I want to cycle through each element of A and compare to the elements of B.
For example: What is safe to drink?
A = ["water";"beer";"ammonia";"bleach";"lemonade"]
B = ["water";"beer"; "lemonade"]
I slapped together this monstrosity but, I'm hoping someone has a more elegant approach:
julia> vcat(filter(w->length(w)!= 0, map(y->filter(z->z!="",(map(x-> begin x==y ? x = y : x = "" end,B))),A))...)
3-element Array{String,1}:
"water"
"beer"
"lemonade"
You can use filter to iterate over the available drinks and in to check whether the current element is in the list of safe drinks:
julia> drinks = ["water", "beer", "bleach"];
julia> safe = ["beer", "lemonade", "water"];
julia> filter(in(safe), drinks)
2-element Array{String,1}:
"water"
"beer"
The filter approach is very neat. You can also use a comprehension:
[a for a in A if a in B]
Related
I have written Julia code in which I initialize an empty array as follows:
a = []
Later in the code, I simply push to this array as follows:
push![a, b]
where b = [c, d, e, ...] is another array, and each b can be of different length.
This works just fine in un-parallelized code. However, I want to do the same thing in parallelized code where a = [] is a shared or distributed array that the different processors can push to.
Neither SharedArray or DArray worked for me. Any advice?
Firstly you should always need to declare what are you holding in your array [] means Any[] and it is almost never a good idea.
Let us consider this vector with placeholders:
julia> a=[Int[] for _ in 1:8]
8-element Vector{Vector{Int64}}:
[]
[]
[]
[]
[]
[]
[]
[]
This Vector contains 8 references to other Vectors.
Let us now distribute it:
julia> using Distributed; addprocs(4);
julia> #everywhere using DistributedArrays
julia> b = distribute(a)
8-element DArray{Vector{Int64}, 1, Vector{Vector{Int64}}}:
[]
[]
[]
[]
[]
[]
[]
[]
This new b is now available through all worker processes where each worker holds its localpart of it. Let us mutate it!
julia> fetch(#spawnat 2 append!(localpart(b)[1], [1,2,3,4]));
julia> fetch(#spawnat 3 append!(localpart(b)[2], [10,20]));
julia> fetch(#spawnat 3 push!(localpart(b)[2], 30))
3-element Vector{Int64}:
10
20
30
We can see that everything is working as expected (we have used fetch to make sure our code actually got executed on remote workers).
Let us know check on the master process the state of b:
julia> b
8-element DArray{Vector{Int64}, 1, Vector{Vector{Int64}}}:
[1, 2, 3, 4]
[]
[]
[10, 20, 30]
[]
[]
[]
[]
You can see that we have successfully used remote workers to mutate b.
I asked a similar question here. I originally followed Prezmyslaw's answer but could not get distribute to distribute an already existing array the way I thought it would for Julia 1.7. What worked for me was defining the array as it was initialized :
using Distributed
addprocs(4)
#everywhere using DistributedArrays
a = distribute([[] for _ in procs()])
#sync #distributed for i = 1:10
b = fill(i, 5)
append!(localpart(a)[1], b) # I swapped push! for append!
end
a
What this does is: first it creates an array with subarrays that are distributed to each worker, then it distributes computation and fills the corresponding subarrays with the values calculated on each worker, finally it merges the subarrays to obtain a full array with all the values.
It is interesting to compare this with the exact same code but substituting a = distribute([[] for _ in procs()]) for a = [[] for _ in procs()]; distribute(a). Evidently the latter does not work as expected (at least for Julia 1.7).
I have an array
array1 = Array{Int,2}(undef, 2, 3)
Is there a way to quickly make a new array that's the same size as the first one? E.g. something like
array2 = Array{Int,2}(undef, size(array1))
current I have to do this which is pretty cumbersome, and even worse for higher dimension arrays
array2 = Array{Int,2}(undef, size(array1)[1], size(array1)[2])
What you're looking for is similar(array1).
You can even change up the array type by passing in a type, e.g.
similar(array1, Float64)
similar(array1, Int64)
Using similar is a great solution. But the reason your original attempt doesn't work is the number 2 in the type parameter signature: Array{Int, 2}. The number 2 specifies that the array must have 2 dimensions. If you remove it you can have exactly as many dimensions as you like:
julia> a = rand(2,4,3,2);
julia> b = Array{Int}(undef, size(a));
julia> size(b)
(2, 4, 3, 2)
This works for other array constructors too:
zeros(size(a))
ones(size(a))
fill(5, size(a))
# etc.
I am trying to return an array of different sized arrays in a Julia function.
In the function, the arrays will be initialized and, in a loop, they will have elements, that are other arrays, pushed to end of the array at each iteration. But I am getting the following error:
MethodError: no method matching push!(::Type{Array{Array{Float64,1},1}}, ::Array{Float64,1})
I am initializing an array of arrays:
x = Array{Array{Float64,1},1}
But when a push! other array, I get the error:
push!(x, y)
In python I would just append the new arrays to a list and return the list, how can I accomplish it in Julia?
Your statement:
julia> x = Array{Array{Float64,1},1}
Array{Array{Float64,1},1}
assigns to x name of the type.
In order to create an instance of this type add () after it:
julia> x = Array{Array{Float64,1},1}()
0-element Array{Array{Float64,1},1}
and now you can push! to it:
julia> push!(x, [2.5, 3.5])
1-element Array{Array{Float64,1},1}:
[2.5, 3.5]
Note that you could have initiated x with an empty vector accepting vectors of Float64 in the following way:
julia> x = Vector{Float64}[]
0-element Array{Array{Float64,1},1}
We use two features here:
Vector{Float64} is a shorthand for Array{Float64, 1}.
If you create an empty vector using [] syntax you can prepend a type of its elements in front of it just like I did in the example.
suppose you want to have a array of matrices and iterate in
a for-loop and add in every loop a matrix to the array, afaik you could do it like this in julia:
V = Array{Array{Float64,2},1}
for i=1:nlevels
img = imgread("/path/img.png")
push!(V, img) # append!(img) doesn't work too
end
MethodError: no method matching append!(::Type{Array{Array{Float64,2},1}}, ::Array{Float64,2})
Closest candidates are:
append!(!Matched::Array{T,1}, ::Any) at collections.jl:21
append!(!Matched::CatIndices.BidirectionalVector{T}, ::Any) at ...
i get this error!
what am i doing wrong here!
How is there right way to achieve this in julia?
A () is what you missed!
Have a look
julia> V = Array{Array{Float64,2},1}
Array{Array{Float64,2},1}
julia> typeof(V)
DataType
julia> V = Array{Array{Float64,2},1}()
0-element Array{Array{Float64,2},1}
julia> typeof(V)
Array{Array{Float64,2},1}
I just started tinkering with Julia and I'm really getting to like it. However, I am running into a road block. For example, in Python (although not very efficient or pythonic), I would create an empty list and append a list of a known size and type, and then convert to a NumPy array:
Python Snippet
a = []
for ....
a.append([1.,2.,3.,4.])
b = numpy.array(a)
I want to be able to do something similar in Julia, but I can't seem to figure it out. This is what I have so far:
Julia snippet
a = Array{Float64}[]
for .....
push!(a,[1.,2.,3.,4.])
end
The result is an n-element Array{Array{Float64,N},1} of size (n,), but I would like it to be an nx4 Array{Float64,2}.
Any suggestions or better way of doing this?
The literal translation of your code would be
# Building up as rows
a = [1. 2. 3. 4.]
for i in 1:3
a = vcat(a, [1. 2. 3. 4.])
end
# Building up as columns
b = [1.,2.,3.,4.]
for i in 1:3
b = hcat(b, [1.,2.,3.,4.])
end
But this isn't a natural pattern in Julia, you'd do something like
A = zeros(4,4)
for i in 1:4, j in 1:4
A[i,j] = j
end
or even
A = Float64[j for i in 1:4, j in 1:4]
Basically allocating all the memory at once.
Does this do what you want?
julia> a = Array{Float64}[]
0-element Array{Array{Float64,N},1}
julia> for i=1:3
push!(a,[1.,2.,3.,4.])
end
julia> a
3-element Array{Array{Float64,N},1}:
[1.0,2.0,3.0,4.0]
[1.0,2.0,3.0,4.0]
[1.0,2.0,3.0,4.0]
julia> b = hcat(a...)'
3x4 Array{Float64,2}:
1.0 2.0 3.0 4.0
1.0 2.0 3.0 4.0
1.0 2.0 3.0 4.0
It seems to match the python output:
In [9]: a = []
In [10]: for i in range(3):
a.append([1, 2, 3, 4])
....:
In [11]: b = numpy.array(a); b
Out[11]:
array([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])
I should add that this is probably not what you actually want to be doing as the hcat(a...)' can be expensive if a has many elements. Is there a reason not to use a 2d array from the beginning? Perhaps more context to the question (i.e. the code you are actually trying to write) would help.
The other answers don't work if the number of loop iterations isn't known in advance, or assume that the underlying arrays being merged are one-dimensional. It seems Julia lacks a built-in function for "take this list of N-D arrays and return me a new (N+1)-D array".
Julia requires a different concatenation solution depending on the dimension of the underlying data. So, for example, if the underlying elements of a are vectors, one can use hcat(a) or cat(a,dims=2). But, if a is e.g a 2D array, one must use cat(a,dims=3), etc. The dims argument to cat is not optional, and there is no default value to indicate "the last dimension".
Here is a helper function that mimics the np.array functionality for this use case. (I called it collapse instead of array, because it doesn't behave quite the same way as np.array)
function collapse(x)
return cat(x...,dims=length(size(x[1]))+1)
end
One would use this as
a = []
for ...
... compute new_a...
push!(a,new_a)
end
a = collapse(a)