Julia allows me to do elementwise binary operators on arrays/matrices with .:
[1 2 3] .+ [3 2 1]
[1 2 3] .> [3 2 1]
Is there a standard way to apply an arbitrary function f elementwise to a pair of arrays?
If you just want to apply a binary function to each pair of values from two lists, you can use map:
f(x,y) = 2x - y^2
julia> map(f, [1, 2, 3], [3, 2, 1])
3-element Array{Int64,1}:
-7
0
5
The .+ and .> operators also have the additional behavior that singleton dimensions are broadcast, like so:
julia> [1, 2, 3] .+ [-1 -2 -3]
3x3 Array{Int64,2}:
0 -1 -2
1 0 -1
2 1 0
julia> rand(3,4) .+ [1, 2, 3]
3x4 Array{Float64,2}:
1.73798 1.84132 1.12923 1.30192
2.10961 2.17835 2.52779 2.3028
3.16457 3.04659 3.67604 3.08869
julia> rand(3,4) .+ [1 2 3 4]
3x4 Array{Float64,2}:
1.40294 2.31384 3.34001 4.60027
1.13289 2.99275 3.50606 4.51049
1.31486 2.7585 3.64655 4.59647
If you also want this kind of behavior, you can use the broadcast function:
julia> broadcast(f, [1 2 3], [3, 2, 1])
3x3 Array{Int64,2}:
-7 -5 -3
-2 0 2
1 3 5
Related
How can I tell if an array contains some element?
I have been manually checking with a loop:
for x in xs
if x == a
return true
end
end
return false
Is there a more idiomatic way?
The in operator will iterate over an array and check if some element exists:
julia> xs = [5, 9, 2, 3, 3, 8, 7]
julia> 8 in xs
true
julia> 1 in xs
false
It is important to remember that missing values can alter the behavior you might otherwise expect:
julia> 2 in [1, missing]
missing
in can be used on general collections. In particular, matrices:
julia> A = [1 4 7
2 5 8
3 6 9]
3×3 Array{Int64,2}:
1 4 7
2 5 8
3 6 9
julia> 7 in A
true
julia> 10 in A
false
When I add a newline to my array definition, the type of my array changes.
julia> a = [[1]]
1-element Array{Array{Int64,1},1}:
[1]
julia> a = [[1]
]
1-element Array{Int64,1}:
1
I thought they both should return the same result i.e. of type Array{Array{Int64,1},1}
In order to understand this see the following:
julia> :([[1]
])
:([[1];])
And you see that adding a newline is rewritten as vcat operation.
The reason for this is to allow writing something like this:
julia> x = [1 2
3 4]
2×2 Array{Int64,2}:
1 2
3 4
and your example is hitting a corner case of this syntax.
Note, however, that without an extra empty line vcat is not called:
julia> :([[1]
])
:([[1]])
Another use-case that is worth to know is:
julia> [[1, 2]
[3, 4]]
4-element Array{Int64,1}:
1
2
3
4
and the same with variables (can improve code readability in some cases):
julia> a = [1,2]
2-element Array{Int64,1}:
1
2
julia> b = [3, 4]
2-element Array{Int64,1}:
3
4
julia> [a
b]
4-element Array{Int64,1}:
1
2
3
4
I understand Julia can apply element-wise argument to a function by f.(x)
in v0.6
x = [1, 2, 3]
f = x->3x
#assert f.(x) = [3, 6, 9]
Now, I define f as Array{Function, 1}.
f1(x) = 3x
f2(x) = 4x
f = [f1, f2]
x = 2
#assert isa(f, Array{Function,1}) == true
# f.(x) is unavailable
I want to apply arguments to element-wise function like above syntax, not using map, [_f(x) for _f in f]
Can someone be familiar with this issue?
You can broadcast the pipe operator (|>), e.g.
x .|> f
You have to take care how to define x and f, in some cases you will fail. Your first x applied on your last f will fail.
julia> 5 .|> [x->2x, x->7x]
2-element Array{Int64,1}:
10
35
julia> [2, 5] .|> [x->2x, x->7x]
2-element Array{Int64,1}:
4
35
julia> [2 5] .|> [x->2x, x->7x]
2-element Array{Int64,2}:
4 10
14 35
julia> [2 5] .|> [x->2x x->7x]
1×2 Array{Int64,2}:
4 35
julia> [2, 5] .|> [x->2x x->7x]
2×2 Array{Int64,2}:
4 14
10 35
julia> [2 3 5] .|> [x->2x x->7x]
ERROR: DimensionMismatch("arrays could not be broadcast to a common")
julia> [2, 3, 5] .|> [x->2x, x->7x]
ERROR: DimensionMismatch("arrays could not be broadcast to a common")
julia> x = [1, 2, 3]; f = [x->2x, x->3x]; x .|> f
ERROR: DimensionMismatch("arrays could not be broadcast to a common")
Here's another possibility:
((f, x)->f(x)).([f1, f2], x)
Is there any easy way to reshape a vector into an array in which the "filling" is by row?
More specifically, suppose I have a vector
v = collect(1:8)
reshape "fills" the resulting array by column:
reshape(v, (2,2,2))
2x2x2 Array{Int64,3}:
[:, :, 1] =
1 3
2 4
[:, :, 2] =
5 7
6 8
But I want to get:
a = Array{Int}(2,2,2)
a[:, :, 1] = [1 2; 3 4]
a[:, :, 2] = [5 6; 7 8]
a
2x2x2 Array{Int64,3}:
[:, :, 1] =
1 2
3 4
[:, :, 2] =
5 6
7 8
This would be a nice option to add to reshape.
mapslices(transpose,reshape(v, (2,2,2)),[1,2])
The keyword you were missing is "transpose". The rest I just took from the docs
I want to initialise a 3-dimensional array in Julia with constant entries. For the 2d case I can use
A = [1 2; 3 4]
Is there a similar short syntax for 3d arrays?
Not at this time, although something like the following isn't too bad
A = zeros(2,2,2)
A[:,:,1] = [1 2; 3 4]
A[:,:,2] = [10 20; 30 40]
One can use either the cat or the reshape functions to accomplish the task: (tested with Julia-1.0.0):
julia> cat([1 2; 3 4], [5 6; 7 8], dims=3)
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 2
3 4
[:, :, 2] =
5 6
7 8
For higher Array dimensions, the cat calls must be nested: cat(cat(..., dims=3), cat(..., dims=3), dims=4).
The reshape function allows building higher dimension Arrays "at once", i.e., without nested calls:
julia> reshape([(1:16)...], 2, 2, 2, 2)
2×2×2×2 Array{Int64,4}:
[:, :, 1, 1] =
1 3
2 4
[:, :, 2, 1] =
5 7
6 8
[:, :, 1, 2] =
9 11
10 12
[:, :, 2, 2] =
13 15
14 16
It is actually possible to declare a multidimensional array in julia using only list comprehension
julia> a = [x + y + z for x in 1:2, y ∈ 2:3, z = 3:4]
2×2×2 Array{Int64,3}:
[:, :, 1] =
6 7
7 8
[:, :, 2] =
7 8
8 9
julia> size(a)
(2, 2, 2)
julia> ndims(a)
3
Julia documentation about Multi-dimensional Arrays is a good place to learn more about array creation.
For a 3-dimensional array, you can do the following:
julia> [1; 2;; 3; 4;; 5; 6;;;
7; 8;; 9; 10;; 11; 12]
2×3×2 Array{Int64, 3}:
[:, :, 1] =
1 3 5
2 4 6
[:, :, 2] =
7 9 11
8 10 12
From the documentation, "... ; and ;; concatenate in the first and second dimension, using more semicolons extends this same general scheme. The number of semicolons in the separator specifies the particular dimension, so ;;; concatenates in the third dimension, ;;;; in the 4th, and so on."