How to exchange one specific value in an array in Julia? - arrays

I'm pretty new to Julia, so this is probably a pretty easy question. I want to create a vector and exchange a given value with a new given value.
This is how it would work in Java, but I can't find a solution for Julia. Do I have to copy the array first? I'm pretty clueless..
function sorted_exchange(v::Array{Int64,1}, in::Int64, out::Int64)
i=1
while v[i]!=out
i+=1
end
v[i]=in
return v
end
The program runs but just returns the "old" vector.
Example: sorted_exchange([1,2,3],4,3), expected:[1,2,4], actual:[1,2,3]

There's a nice built-in function for this: replace or its in-place version: replace!:
julia> v = [1,2,3];
julia> replace!(v, 3=>4);
julia> v
3-element Array{Int64,1}:
1
2
4
The code you have posted seems to work fine, though it does something slightly different. Your code only replaces the first instance of 3, while replace! replaces every instance. If you just want the first instance to be replaced you can write:
julia> v = [1,2,3,5,3,5];
julia> replace!(v, 3=>4; count=1)
6-element Array{Int64,1}:
1
2
4
5
3
5

You can find the value you want to replace using findall:
a = [1, 2, 5]
findall(isequal(5), a) # returns 3, the index of the 5 in a
and use that to replace the value
a[findall(isequal(5), a)] .= 6
a # returns [1, 2, 6]

Related

Julia Quick way to initialise an empty array that's the same size as another?

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.

Sorted version of in

I have an array of times event_times and I want to check if t in event_times. However, I know that event_times is sorted. Is there a way to make use of that to make the search faster?
An idiomatic Julian way would be an elaboration of:
struct SortedVector{T,V<:AbstractVector} <: AbstractVector{T}
v::V
SortedVector{T,V}(v::AbstractVector{T}) where {T, V} = new(v)
# check sorted in inner constructor??
end
SortedVector(v::AbstractVector{T}) where T = SortedVector{T,typeof(v)}(v)
#inline Base.size(sv::SortedVector) = size(sv.v)
#inline Base.getindex(sv::SortedVector,i) = sv.v[i]
#inline Base.in(e::T,sv::SortedVector{T}) where T = !isempty(searchsorted(sv.v,e))
And then:
julia> v = SortedVector(sort(rand(1:10,10)))
10-element SortedVector{Int64,Array{Int64,1}}:
1
4
5
5
6
6
6
7
7
10
julia> 3 in v
false
julia> 1 in v
true
If I recall correctly David Sanders had an implementation with this name. Perhaps looking at https://github.com/JuliaIntervals/IntervalOptimisation.jl/blob/889bf43e8a514e696869baaa6af1300ace87b90b/src/SortedVectors.jl would promote reuse.
Following #ColinTBowers's hint, you can use the fact that searchsorted returns a range which is empty iff t is not in event_times. Thus !isempty(searchsorted(event_times,t)) is a fast method to get the answer.

arr.delete() vs arr.delete_at() in Ruby

I wrote the function below which accepts an array and returns a randomized version of it.
I've noticed that I sometimes end up with a nil element in randomizedArr when using list.delete(element) to remove an element from the array, but this does not happen when using list.delete_at(index) -- note that the latter is commented out in the below snippet. Am I missing something?
If there's a better way to do what I'm trying to achieve with this function then I would appreciate any suggestion. Thanks!
The array I'm passing to this function is a string array with ~2k elements. I'm passing in a clone of the original array so it doesn't become empty when the function is called. I'm using Ruby 2.1 on Windows 7.
def getRandomList(list)
randomizedArr = Array.new()
cnt = list.length
while (cnt >= 1) do
index = rand(cnt)
prod = list[index]
randomizedArr.push(prod)
list.delete(prod)
#list.delete_at(index)
cnt = cnt - 1
end
if randomizedArr.include?(nil)
puts "found nil element"
end
return randomizedArr
end #getRandomList()
I am not sure why you need to put all that logic when you can randomize the list by list.shuffle.
Refering to the Ruby documentation this is what I found to answer your question...
#To delete an element at a particular index:
arr = [2, 3, 4, 5] #I added this bit
arr.delete_at(2) #=> 4
arr #=> [2, 3, 5]
#To delete a particular element anywhere in an array, use delete:
arr = [1, 2, 2, 3]
arr.delete(2) #=> 2
arr #=> [1,3]
All of that can be found here https://ruby-doc.org/core-2.4.1/Array.html
arr.delete(2) will remove any instance of 2 in an array while delete_at(2) only removes the third value in the array.

Julia Approach to python equivalent list of lists

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)

Scala: what is the best way to append an element to an Array?

Say I have an Array[Int] like
val array = Array( 1, 2, 3 )
Now I would like to append an element to the array, say the value 4, as in the following example:
val array2 = array + 4 // will not compile
I can of course use System.arraycopy() and do this on my own, but there must be a Scala library function for this, which I simply could not find. Thanks for any pointers!
Notes:
I am aware that I can append another Array of elements, like in the following line, but that seems too round-about:
val array2b = array ++ Array( 4 ) // this works
I am aware of the advantages and drawbacks of List vs Array and here I am for various reasons specifically interested in extending an Array.
Edit 1
Thanks for the answers pointing to the :+ operator method. This is what I was looking for. Unfortunately, it is rather slower than a custom append() method implementation using arraycopy -- about two to three times slower. Looking at the implementation in SeqLike[], a builder is created, then the array is added to it, then the append is done via the builder, then the builder is rendered. Not a good implementation for arrays. I did a quick benchmark comparing the two methods, looking at the fastest time out of ten cycles. Doing 10 million repetitions of a single-item append to an 8-element array instance of some class Foo takes 3.1 sec with :+ and 1.7 sec with a simple append() method that uses System.arraycopy(); doing 10 million single-item append repetitions on 8-element arrays of Long takes 2.1 sec with :+ and 0.78 sec with the simple append() method. Wonder if this couldn't be fixed in the library with a custom implementation for Array?
Edit 2
For what it's worth, I filed a ticket:
https://issues.scala-lang.org/browse/SI-5017
You can use :+ to append element to array and +: to prepend it:
0 +: array :+ 4
should produce:
res3: Array[Int] = Array(0, 1, 2, 3, 4)
It's the same as with any other implementation of Seq.
val array2 = array :+ 4
//Array(1, 2, 3, 4)
Works also "reversed":
val array2 = 4 +: array
Array(4, 1, 2, 3)
There is also an "in-place" version:
var array = Array( 1, 2, 3 )
array +:= 4
//Array(4, 1, 2, 3)
array :+= 0
//Array(4, 1, 2, 3, 0)
The easiest might be:
Array(1, 2, 3) :+ 4
Actually, Array can be implcitly transformed in a WrappedArray

Resources