What does the following Go array operation do? - arrays

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.

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.

Convert an integer array to string array in Julia

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.

Why is it not possible to fill an array using an each do loop in Ruby?

If I use an each do loop to fill an array, it will leave the array as it is (in this case it will be a nil array of size 4)
array = Array.new(4)
array.each do |i|
i = 5
end
I understand that I can initialize an array with my desired value using array = Array.new(4) {desired value} but there are situations in which I'm choosing between different values and I am trying to understand how the each do loop work exactly.
The current way I'm doing it is the following which fills in the array with my desired value
array = Array.new(4)
array.each_with_index do |val, i|
array[i] = 5
end
Solution
You need :
array = Array.new(4) do |i|
5
# or some logic depending on i (the index between 0 and 3)
end
Your code
array = Array.new(4)
array is now an Array with 4 elements (nil each time).
array.each iterates over those 4 elements (still nil), and sets i as block-local variable equal to nil.
Inside this block, you override i with 5, but you don't do anything with it. During the next iteration, i is set back to nil, and to 5, and so on...
You don't change the original array, you only change local variables that have been set equal to the array elements.
The difference is that
i = 5
is an assignment. It assigns the value 5 to the variable i.
In Ruby, assignments only affect the local scope, they don't change the variable in the caller's scope:
def change(i)
i = 5 # <- doesn't work as you might expect
end
x = nil
change(x)
x #=> nil
It is therefore impossible to replace an array element with another object by assigning to a variable.
On the other hand,
array[i] = 5
is not an assignment, but a disguised method invocation. It's equivalent to:
array.[]=(i, 5)
or
array.public_send(:[]=, i, 5)
It asks the array to set the element at index i to 5.

How do concatenation and indexing differ for cells and arrays in MATLAB?

I am a little confused about the usage of cells and arrays in MATLAB and would like some clarification on a few points. Here are my observations:
An array can dynamically adjust its own memory to allow for a dynamic number of elements, while cells seem to not act in the same way:
a=[]; a=[a 1]; b={}; b={b 1};
Several elements can be retrieved from cells, but it doesn't seem like they can be from arrays:
a={'1' '2'}; figure; plot(...); hold on; plot(...); legend(a{1:2});
b=['1' '2']; figure; plot(...); hold on; plot(...); legend(b(1:2));
%# b(1:2) is an array, not its elements, so it is wrong with legend.
Are these correct? What are some other different usages between cells and array?
Cell arrays can be a little tricky since you can use the [], (), and {} syntaxes in various ways for creating, concatenating, and indexing them, although they each do different things. Addressing your two points:
To grow a cell array, you can use one of the following syntaxes:
b = [b {1}]; % Make a cell with 1 in it, and append it to the existing
% cell array b using []
b = {b{:} 1}; % Get the contents of the cell array as a comma-separated
% list, then regroup them into a cell array along with a
% new value 1
b{end+1} = 1; % Append a new cell to the end of b using {}
b(end+1) = {1}; % Append a new cell to the end of b using ()
When you index a cell array with (), it returns a subset of cells in a cell array. When you index a cell array with {}, it returns a comma-separated list of the cell contents. For example:
b = {1 2 3 4 5}; % A 1-by-5 cell array
c = b(2:4); % A 1-by-3 cell array, equivalent to {2 3 4}
d = [b{2:4}]; % A 1-by-3 numeric array, equivalent to [2 3 4]
For d, the {} syntax extracts the contents of cells 2, 3, and 4 as a comma-separated list, then uses [] to collect these values into a numeric array. Therefore, b{2:4} is equivalent to writing b{2}, b{3}, b{4}, or 2, 3, 4.
With respect to your call to legend, the syntax legend(a{1:2}) is equivalent to legend(a{1}, a{2}), or legend('1', '2'). Thus two arguments (two separate characters) are passed to legend. The syntax legend(b(1:2)) passes a single argument, which is a 1-by-2 string '12'.
Every cell array is an array! From this answer:
[] is an array-related operator. An array can be of any type - array of numbers, char array (string), struct array or cell array. All elements in an array must be of the same type!
Example: [1,2,3,4]
{} is a type. Imagine you want to put items of different type into an array - a number and a string. This is possible with a trick - first put each item into a container {} and then make an array with these containers - cell array.
Example: [{1},{'Hallo'}] with shorthand notation {1, 'Hallo'}

Resources