Convert an integer array to string array in Julia - arrays

Is there a way to convert an array of integers (or any numbers) to an array of strings in Julia? Essentially, I want to convert [1 2 3 4] to ["1" "2" "3" "4"].
Stuff that doesn't work:
numbers = [1 2 3 4];
strings = ["1" "2" "3" "4"];
string(numbers)
convert(Array{String}, numbers)
Output:
"[1 2 3 4]"
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type String
...
I'm using Juila 1.3.1

Surprisingly, this doesn't appear to be a duplicate.
For a single number, you use the string function. For an array of numbers, you need to broadcast the string function to each element of the array. The simplest way to do this in Julia is using the . syntax, e.g.:
x = [1,2,3,4]
y = string.(x)
Note, broadcasting works for any function (including user-defined functions). So, e.g.:
f(x) = x^2
f.([1,2,3,4])
just works.

Related

Filling the array with array does not work as I expected

I want to make a multiple array whose entry is multiple array, and want to push some array one by one into the entry.
For example, I made 2 x 3 Matrix named arr and tried to fill [1,1] and [1,2] entries with 4 x 4 Matrix spawned by randn(4,4).
arr = fill(Matrix{Float64}[], 2, 3)
push!(arr[1,1],randn(4,4))
push!(arr[1,2],randn(4,4))
println(arr[1,1])
println(arr[1,2])
println(arr[1,3])
However, the result is all the entries of arr (other than [1,1] and [1,2]) were filled with the same randn(4,4), instead of just [1,1] and [1,2] filled with randn(4,4):
[[-0.15122805007483328 0.6132236453930502 -0.9090110366765862 1.2589924202099898; -1.120611384326006 -0.9083935218058066 0.7252290006516056 1.0970416725786256; -0.19173238706933265 1.3610525411901113 -0.05258697093572793 0.7776085390912448; 0.18491459001855373 -2.0537142669734934 0.3482557186126859 0.0047622478008474845], [0.23422967703060255 -0.51986351753462 0.45947166573674303 0.31316899298864387; 0.3704450103622709 -0.8186574197233013 -0.9990329964554037 -0.8345957519924763; 0.56641529964098 -0.8393435538481216 -0.6379336546939682 1.1843452368116358; 0.9435767553275002 0.0033471181565433127 -1.191611491619908 1.3970554854927264]]
[[-0.15122805007483328 0.6132236453930502 -0.9090110366765862 1.2589924202099898; -1.120611384326006 -0.9083935218058066 0.7252290006516056 1.0970416725786256; -0.19173238706933265 1.3610525411901113 -0.05258697093572793 0.7776085390912448; 0.18491459001855373 -2.0537142669734934 0.3482557186126859 0.0047622478008474845], [0.23422967703060255 -0.51986351753462 0.45947166573674303 0.31316899298864387; 0.3704450103622709 -0.8186574197233013 -0.9990329964554037 -0.8345957519924763; 0.56641529964098 -0.8393435538481216 -0.6379336546939682 1.1843452368116358; 0.9435767553275002 0.0033471181565433127 -1.191611491619908 1.3970554854927264]]
[[-0.15122805007483328 0.6132236453930502 -0.9090110366765862 1.2589924202099898; -1.120611384326006 -0.9083935218058066 0.7252290006516056 1.0970416725786256; -0.19173238706933265 1.3610525411901113 -0.05258697093572793 0.7776085390912448; 0.18491459001855373 -2.0537142669734934 0.3482557186126859 0.0047622478008474845], [0.23422967703060255 -0.51986351753462 0.45947166573674303 0.31316899298864387; 0.3704450103622709 -0.8186574197233013 -0.9990329964554037 -0.8345957519924763; 0.56641529964098 -0.8393435538481216 -0.6379336546939682 1.1843452368116358; 0.9435767553275002 0.0033471181565433127 -1.191611491619908 1.3970554854927264]]
What is wrong?
Any information would be appreciated.
When you do arr = fill(Matrix{Float64}[], 2, 3) all 6 elements point into exactly the same location in memory because fill does not make deep copy - it just copies the references. Basically, using fill when the first argument is mutable usually turns out not to be a good idea.
Hence what you actually want is:
arr = [Matrix{Float64}[] for i in 1:2, j in 1:3]
Now each of 6 slots will have its own address in the memory.
This way of creating the array implies that each element will be Float64, i.e. a scalar. You need to fix the type signature. So for instance you could do
D = Matrix{Array{Float64, 2}}(undef, 2, 3)
if you want it to have 2-dimensional arrays as elements (the Float64,2 does that)
and then allocate
D[1,1] = rand(4,4)
D[1,2] = rand(4,4)
to give you (or rather, me!):
julia> D[1,1]
4×4 Matrix{Float64}:
0.210019 0.528594 0.0566622 0.0547953
0.729212 0.40829 0.816365 0.804139
0.39524 0.940286 0.976152 0.128008
0.886597 0.379621 0.153302 0.798803
julia> D[1,2]
4×4 Matrix{Float64}:
0.640809 0.821668 0.627057 0.382058
0.532567 0.262311 0.916391 0.200024
0.0599815 0.17594 0.698521 0.517822
0.965279 0.804067 0.39408 0.105774

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.

Initialize array of arrays for construction on the fly

How do you declare an array that contain arrays in julia?
I have a=Int32[] which creates an empty array of Int32 (of course), but I would like later to construct on the fly something like
if ...
push!(a, [r,s]) # (*)
...
where r and s are integers. I tried a=Int32[Int32[]] but it does not work when doing (*). I don't have the specific shape of a, so I need to declare it without this restriction.
Int32[] creates a Vector{Int32} which is a Vector with element type Int32. You want a Vector with element type Vector{Int32}, so you can use Vector{Vector{Int32}}() or Vector{Int32}[]. Note that Vector{T} is an alias for Array{T,1}, aka an Array with element type T and 1 dimension, so when Julia prints out the type, it won't use the word Vector.
julia> v=Vector{Vector{Int32}}()
0-element Array{Array{Int32,1},1}
julia> push!(v,[1,2,3])
1-element Array{Array{Int32,1},1}:
Int32[1, 2, 3]
or
julia> x=Vector{Int32}[]
0-element Array{Array{Int32,1},1}
julia> push!(x,[4,5,6])
1-element Array{Array{Int32,1},1}:
Int32[4, 5, 6]

What does the following Go array operation do?

I am confused about how the following code works, especially what is the purpose of "..."
array = append(array[:i], array[i+1:]...)
The line
a = append(a[:i], a[i+1:]...)
creates a new slice by removing the item at position i in a, by combining the items from 0 to i (not included), and from i+1 to the end.
Your second question is what is the purpose of .... append accepts a slice as first argument, and an unlimited number of arguments, all with a type assignable to the type of its elements.
append is defined as
func append(slice []Type, elems ...Type) []Type
Writing
a = append(a[:i], a[i+1:]...)
is equivalent as writing
a = append(a[:i], a[i+1], a[i+2], a[i+3], a[i+4]) //and so on, until the end of the slice.
Using a[i+1:]... is basically a shorthand syntax, as the Go spec describes in https://golang.org/ref/spec#Passing_arguments_to_..._parameters:
If f is variadic with a final parameter p of type ...T, then within f the type of p is equivalent to type []T. If f is invoked with no actual arguments for p, the value passed to p is nil. Otherwise, the value passed is a new slice of type []T with a new underlying array whose successive elements are the actual arguments, which all must be assignable to T
Playground
array = append(array[:i], array[i+1:]...)
is removing an element at index i
but another thing to point out is that slice is backed by an underlying array. For example:
package main
import (
"fmt"
)
func main() {
myArray := [6]int {1,2,3,4,5,6}
mySlice := myArray[:]
fmt.Println("myArray before append: ", myArray)
i := 3
mySlice = append(mySlice[:i], mySlice[i+1:]...)
fmt.Println("mySlice after append: ", mySlice)
fmt.Println("myArray after append: ", myArray)
}
Result:
myArray before append: [1 2 3 4 5 6]
mySlice after append: [1 2 3 5 6]
myArray after append: [1 2 3 5 6 6]
goplayground
In the underlying [1,2,3] stayed in place, that data never go moved anywhere, while [5,6] which were given by b[i+1] were appended to [1,2,3], and thus overwrote [3,4]; the other [6] stayed in place.
Even though you get different copy of a slice the underlying array will be the same*, this makes append a much more efficient operation then if the whole underlying array had to be copied over!
*If underlying array exceeds it's capacity, a new larger array will be allocated and values from old array would be copied to the new array, but this will never happen when removing an element.
Built-in func append is Variadic Function.
To pass slice argument to any variadic function, you have to use ...
Go lang spec: Passing arguments to ... parameters
If f is variadic with final parameter type ...T, then within the
function the argument is equivalent to a parameter of type []T. At
each call of f, the argument passed to the final parameter is a new
slice of type []T whose successive elements are the actual arguments,
which all must be assignable to the type T. The length of the slice is
therefore the number of arguments bound to the final parameter and may
differ for each call site.
This line would give you a result value removing position i.
array = append(array[:i], array[i+1:]...)
Let's say, we have
array := []int{1, 2, 3, 4, 5, 6, 7}
i := 3
fmt.Println("Original slice:", array)
part1 := array[:i]
part2 := array[i+1:]
fmt.Println("part1:", part1)
fmt.Println("part2:", part2)
array = append(array[:i], array[i+1:]...)
fmt.Println("Result slice:", array)
Output:
Original slice: [1 2 3 4 5 6 7]
part1: [1 2 3]
part2: [5 6 7]
Result slice: [1 2 3 5 6 7]
Play Link: https://play.golang.org/p/_cIk0VcD6w
The purpose of ... is to save you typing individual elements as the append method takes first argument as slice and then variable number of arguments for elements to be appended.
i.e. You actually need to call append as
append(sliceName[:i], array[i+1], array[i+2], array[i+3], array[i+4])
but to avoid typing long list of elements, you can simply use ... after the slice or array to spread it as individual elements to be passed as arguments.

Multiple assignment in Scala without using Array?

I have an input something like this: "1 2 3 4 5".
What I would like to do, is to create a set of new variables, let a be the first one of the sequence, b the second, and xs the rest as a sequence (obviously I can do it in 3 different lines, but I would like to use multiple assignment).
A bit of search helped me by finding the right-ignoring sequence patterns, which I was able to use:
val Array(a, b, xs # _*) = "1 2 3 4 5".split(" ")
What I do not understand is that why doesn't it work if I try it with a tuple? I get an error for this:
val (a, b, xs # _*) = "1 2 3 4 5".split(" ")
The error message is:
<console>:1: error: illegal start of simple pattern
Are there any alternatives for multiple-assignment without using Array?
I have just started playing with Scala a few days ago, so please bear with me :-) Thanks in advance!
Other answers tell you why you can't use tuples, but arrays are awkward for this purpose. I prefer lists:
val a :: b :: xs = "1 2 3 4 5".split(" ").toList
Simple answer
val Array(a, b, xs # _*) = "1 2 3 4 5".split(" ")
The syntax you are seeing here is a simple pattern-match. It works because "1 2 3 4 5".split(" ") evaluates to an Array:
scala> "1 2 3 4 5".split(" ")
res0: Array[java.lang.String] = Array(1, 2, 3, 4, 5)
Since the right-hand-side is an Array, the pattern on the left-hand-size must, also, be an Array
The left-hand-side can be a tuple only if the right-hand-size evaluates to a tuple as well:
val (a, b, xs) = (1, 2, Seq(3,4,5))
More complex answer
Technically what's happening here is that the pattern match syntax is invoking the unapply method on the Array object, which looks like this:
def unapplySeq[T](x: Array[T]): Option[IndexedSeq[T]] =
if (x == null) None else Some(x.toIndexedSeq)
Note that the method accepts an Array. This is what Scala must see on the right-hand-size of the assignment. And it returns a Seq, which allows for the #_* syntax you used.
Your version with the tuple doesn't work because Tuple3's unapplySeq is defined with a Product3 as its parameter, not an Array:
def unapply[T1, T2, T3](x: Product3[T1, T2, T3]): Option[Product3[T1, T2, T3]] =
Some(x)
You can actually "extractors" like this that do whatever you want by simply creating an object and writing an unapply or unapplySeq method.
The answer is:
val a :: b :: c = "1 2 3 4 5".split(" ").toList
Should clarify that in some cases one may want to bind just the first n elements in a list, ignoring the non-matched elements. To do that, just add a trailing underscore:
val a :: b :: c :: _ = "1 2 3 4 5".split(" ").toList
That way:
c = "3" vs. c = List("3","4","5")
I'm not an expert in Scala by any means, but I think this might have to do with the fact that Tuples in Scala are just syntatic sugar for classes ranging from Tuple2 to Tuple22.
Meaning, Tuples in Scala aren't flexible structures like in Python or other languages of the sort, so it can't really create a Tuple with an unknown a priori size.
We can use pattern matching to extract the values from string and assign it to multiple variables. This requires two lines though.
Pattern says that there are 3 numbers([0-9]) with space in between. After the 3rd number, there can be text or not, which we don't care about (.*).
val pat = "([0-9]) ([0-9]) ([0-9]).*".r
val (a,b,c) = "1 2 3 4 5" match { case pat(a,b,c) => (a,b,c) }
Output
a: String = 1
b: String = 2
c: String = 3

Resources