Related
Julia's "higher-order" function "map" looks very useful. But while it is easy to understand how it can be used on functions that have one input, it is not obvious how map can be used when the function has multiple inputs, and when each these may be arrays. I would like discover how map is used in that situation.
Suppose I have the following function:
function randomSample(items, weights)
sample(items, Weights(weights))
end
Example:
Pkg.add("StatsBase")
using StatsBase
randomSample([1,0],[0.5, 0.5])
How can map be used here? I have tried something like:
items = [1 0;1 0;1 0]
weights = [1 0;0.5 0.5;0.75 0.25]
map(randomSample(items,weights))
In the example above, I would expect Julia to output a 3 by 1 array of integers (from the items), each row being either 0 or 1 depending on the corresponding weights.
In your case when items and weights are Matrix you can use the eachrow function like this:
map(randomSample, eachrow(items), eachrow(weights))
If you are on Julia version earlier than 1.1 you can write:
map(i -> randomSample(items[i, :], weights[i, :]), axes(items, 1))
or
map(i -> randomSample(view(items,i, :), view(weights, i, :)), axes(items, 1))
(the latter avoids allocations)
However, in practice I would probably define items and weights as vectors of vectors:
items = [[1, 0],[1, 0],[1, 0]]
weights = [[1, 0], [0.5, 0.5], [0.75, 0.25]]
and then you can simply write:
map(randomSample, items, weights)
or
randomSample.(items, weights)
The reason for my preference is the following:
it is conceptually clearer what is the structure of your data
vector of vectors is easier to mutate (e.g. you can push! a new entry at the end)
vector of vectors can be ragged if needed
in some cases it might be a bit faster (iterating by rows in Julia is not optimal as it uses column-major indexing; of course you can fix it in your Matrix approach by assuming that you store your data columnwise not colwise as you currently do)
(this is not a very strong preference and you can probably choose whatever is more convenient to you)
I have an Array of arrays, called y:
y=Array(Vector{Int64}, 10)
which is basically a list of 1-dimensional arrays(10 of them), and each 1-dimensional array has length 5. Below is an example of how they are initialized:
for i in 1:10
y[i]=sample(1:20, 5)
end
Each 1-dimensional array includes 5 randomly sampled integers between 1 to 20.
Right now I am applying a map function where for each of those 1-dimensional arrays in y , excludes which numbers from 1 to 20:
map(x->setdiff(1:20, x), y)
However, I want to make sure when the function applied to y[i], if the output of setdiff(1:20, y[i]) includes i, i is excluded from the results. in other words I want a function that works like
setdiff(deleteat!(Vector(1:20),i) ,y[i])
but with map.
Mainly my question is that whether you can access the index in the map function.
P.S, I know how to do it with comprehensions, I wanted to know if it is possible to do it with map.
comprehension way:
[setdiff(deleteat!(Vector(1:20), index), value) for (index,value) in enumerate(y)]
Like this?
map(x -> setdiff(deleteat!(Vector(1:20), x[1]),x[2]), enumerate(y))
For your example gives this:
[2,3,4,5,7,8,9,10,11,12,13,15,17,19,20]
[1,3,5,6,7,8,9,10,11,13,16,17,18,20]
....
[1,2,4,7,8,10,11,12,13,14,15,16,17,18]
[1,2,3,5,6,8,11,12,13,14,15,16,17,19,20]
I would like to create an empty vector and append to it an array in Julia. How do I do that?
x = Vector{Float64}
append!(x, rand(10))
results in
`append!` has no method matching append!(::Type{Array{Float64,1}}, ::Array{Float64,1})
Thanks.
Your variable x does not contain an array but a type.
x = Vector{Float64}
typeof(x) # DataType
You can create an array as Array(Float64, n)
(but beware, it is uninitialized: it contains arbitrary values) or zeros(Float64, n),
where n is the desired size.
Since Float64 is the default, we can leave it out.
Your example becomes:
x = zeros(0)
append!( x, rand(10) )
I am somewhat new to Julia and came across this question after getting a similar error. To answer the original question for Julia version 1.2.0, all that is missing are ():
x = Vector{Float64}()
append!(x, rand(10))
This solution (unlike x=zeros(0)) works for other data types, too. For example, to create an empty vector to store dictionaries use:
d = Vector{Dict}()
push!(d, Dict("a"=>1, "b"=>2))
A note regarding use of push! and append!:
According to the Julia help, push! is used to add individual items to a collection, while append! adds an collection of items to a collection. So, the following pieces of code create the same array:
Push individual items:
a = Vector{Float64}()
push!(a, 1.0)
push!(a, 2.0)
Append items contained in an array:
a = Vector{Float64}()
append!(a, [1.0, 2.0])
You can initialize an empty Vector of any type by typing the type in front of []. Like:
Float64[] # Returns what you want
Array{Float64, 2}[] # Vector of Array{Float64,2}
Any[] # Can contain anything
New answer, for Julia 1. append! is deprecated, you now need to use push!(array, element) to add elements to an array
my_stuff = zeros()
push!(my_stuff, "new element")
I'm trying to create an array of two arrays. However, a = [[1, 2], [3, 4]] doesn't do that, it actually concats the arrays. This is true in Julia: [[1, 2], [3, 4]] == [1, 2, 3, 4]. Any idea?
As a temporary workaround, I use push!(push!(Array{Int, 1}[], a), b).
If you want an array of arrays as opposed to a matrix (i.e. 2-dimensional Array):
a = Array[ [1,2], [3,4] ]
You can parameterize (specify the type of the elements) an Array literal by putting the type in front of the []. So here we are parameterizing the Array literal with the Array type. This changes the interpretation of brackets inside the literal declaration.
Sean Mackesey's answer will give you something of type Array{Array{T,N},1} (or Array{Array{Int64,N},1}, if you put the type in front of []). If you instead want something more strongly typed, for example a vector of vectors of Int (i.e. Array{Array{Int64,1},1}), use the following:
a = Vector{Int}[ [1,2], [3,4] ]
In Julia v0.5, the original syntax now produces the desired result:
julia> a = [[1, 2], [3, 4]]
2-element Array{Array{Int64,1},1}:
[1,2]
[3,4]
julia> VERSION
v"0.5.0"
For a general answer on constructing Arrays of type Array:
In Julia, you can have an Array that holds other Array type objects. Consider the following examples of initializing various types of Arrays:
A = Array{Float64}(10,10) # A single Array, dimensions 10 by 10, of Float64 type objects
B = Array{Array}(10,10,10) # A 10 by 10 by 10 Array. Each element is an Array of unspecified type and dimension.
C = Array{Array{Float64}}(10) ## A length 10, one-dimensional Array. Each element is an Array of Float64 type objects but unspecified dimensions
D = Array{Array{Float64, 2}}(10) ## A length 10, one-dimensional Array. Each element of is an 2 dimensional array of Float 64 objects
Consider for instance, the differences between C and D here:
julia> C[1] = rand(3)
3-element Array{Float64,1}:
0.604771
0.985604
0.166444
julia> D[1] = rand(3)
ERROR: MethodError:
rand(3) produces an object of type Array{Float64,1}. Since the only specification for the elements of C are that they be Arrays with elements of type Float64, this fits within the definition of C. But, for D we specified that the elements must be 2 dimensional Arrays. Thus, since rand(3) does not produce a 2 dimensional array, we cannot use it to assign a value to a specific element of D
Specify Specific Dimensions of Arrays within an Array
Although we can specify that an Array will hold elements which are of type Array, and we can specify that, e.g. those elements should be 2-dimensional Arrays, we cannot directly specify the dimenions of those elements. E.g. we can't directly specify that we want an Array holding 10 Arrays, each of which being 5,5. We can see this from the syntax for the Array() function used to construct an Array:
Array{T}(dims)
constructs an uninitialized dense array with element type T. dims may be a tuple or a series of integer arguments. The syntax Array(T, dims) is also available, but deprecated.
The type of an Array in Julia encompasses the number of the dimensions but not the size of those dimensions. Thus, there is no place in this syntax to specify the precise dimensions. Nevertheless, a similar effect could be achieved using an Array comprehension:
E = [Array{Float64}(5,5) for idx in 1:10]
For those wondering, in v0.7 this is rather similar:
Array{Array{Float64,1},2}(undef, 10,10) #creates a two-dimensional array, ten rows and ten columns where each element is an array of type Float64
Array{Array{Float64, 2},1}(undef,10) #creates a one-dimensional array of length ten, where each element is a two-dimensional array of type Float64
You probably want a matrix:
julia> a = [1 2; 3 4]
2x2 Int64 Array:
1 2
3 4
Maybe a tuple:
julia> a = ([1,2],[3,4,5])
([1,2],[3,4,5])
You can also do {[1,2], [3,4]} which creates an Array{Any,1} containing [1,2] and [3,4] instead of an Array{Array{T,N},1}.
I have a solution list as below from solving a linear equation system:
w[2, 2] -> 0.0000183294,
w[2, 3] -> 0.0000296603,
w[2, 4] -> 0.0000233449,
w[3, 2] -> 0.0000230831,
When I call, for example: w[3,2] I get w[3,2] as output instead of 0.0000230831.
How can I assign these answers to a 2D array named so W[i,j] such that I can call them by their indices?
Solution lists are replacement rules and to get them to work you have to apply the rules. Lets say that you have a Solve[] statement that produces your solution list, the following will create a function W[i,j] that will return the value of w[i,j] if it exists in the list.
sol = Solve[...];
W[i_, j_] := w[i, j] /. sol
As an aside, you should understand that single brackets F[i,j,...] denote a function of the variables i, j, ... and double brackets F[[i,j]] denote a 2D array with indexes i and j. In general it is faster and better to use replacement lists to build functions than it is to make arrays out of them.