Send array from index 1 to function - arrays

I've this function and and I got values which I need to use from args
Run: func(cmd *cobra.Command, args []string) {
....
myFunc(args)
}
I need to pass to myFunc all the args from index 1 and not 0.
of course I can loop and create another array from index 1 but
this duplicate almost all the values except index 0 , is there a way to avoid it in GO?

Yes, simply slice the args slice, and pass that:
myFunc(args[1:])
args is a slice, not an array. You can (re-)slice slices, which will be a contiguous subpart of the original slice. For example:
args[1:4]
The above would be another slice, holding only the following elements from args:
args[1], args[2], args[3]
The upper limit is exclusive. A missing upper index defaults to the length, a missing lower index defaults to 0. These are all detailed in Spec: Slice expressions.
Note that slicing a slice does not copy the elements: it will point to the same underlying array which actually holds the elements. A slice is just a small, struct-like header containing a pointer to the underlying array.
Note that if args is empty, the above would result in a run-time panic. To avoid that, first check its length:
if len(args) == 0 {
myFunc(nil) // or an empty slice: []string{}
} else {
myFunc(args[1:])
}

Related

Ranging over map keys of array type and slicing each array gives the same array for each iteration

When trying to add int array keys of a map to a slice of int slices, ranging and using arr[:] to slice array doesn't work as expected. The resultant slice contains only duplicates of the "first" key in the map(commented out for loop). However, copying the array key to another variable and slicing the new variable works, and the resultant slice contains distinct map key values. I wonder why the copying is necessary. Isn't k, the array key, copied from the map as a new array at each iteration? I don't know where to find documentation regarding this behavior, and would appreciate links and resources :-)
ansSlice := [][]int{}
//ans is a map with [3]int key type
/* For some reason, this doesn't work, and appends values from the same array to ansSlice
for k, _ := range ans {
ansSlice = append(ansSlice, k[:])
}*/
// however, this works
for k, _ := range ans {
key := k
ansSlice = append(ansSlice, key[:])
}
Since the map key type is an array, the assignment:
for k,_ := range ans {
will rewrite k for every iteration. This will rewrite the contents of the array k. The slice k[:] points to k as the underlying array, so all the slices with k as their underlying array will be overwritten as well.
Copy the array for each iteration, as you did. That will create separate arrays for the slices you append.

How slice works in GO?

a = make([]int, 7, 15)
creates implicit array of size 15 and slice(a) creates a shallow copy of implicit array and points to first 7 elements in array.
Consider,
var a []int;
creates a zero length slice that does not point to any implicit array.
a = append(a, 9, 86);
creates new implicit array of length 2 and append values 9 and 86. slice(a) points to that new implicit array, where
len(a) is 2 and cap(a) >= 2
My question:
is this the correct understanding?
As I mentioned "Declare slice or make slice?", the zero value of a slice (nil) acts like a zero-length slice.
So you can append to a []int directly.
You would need to make a slice (make([]int, 0) ) only if you wanted to potentially return an empty slice (instead of nil).
If not, no need to allocate memory before starting appending.
See also "Arrays, slices (and strings): The mechanics of 'append': Nil"
a nil slice is functionally equivalent to a zero-length slice, even though it points to nothing. It has length zero and can be appended to, with allocation.

Is there any better way to handle slices of variable size?

please see the code below
names := make([]string, 0, 100)
names = append(names, "Jack")
names = append(names, "Jacob")
// adding many names in here
Given a circumstances like this: I will get these names from somewhere else, before that I didn't know the size of it. So I a need a dynamic array to contains these names. The above code is way that I came up with. I was wonder if there is any more elegant way to do this.
If I initialise like this
names := make([]string, 100, 200)
// then I use append in here
// I would get first 100 elements as empty, the append start at index 101.
I suppose this would be a such waste on memory.
I am totally new to static programming language, so if there is any wrong concept in this post, please point it out.
Just only declare the type and then assign the appended slice to it:
package main
import "fmt"
func main() {
var names []string
names = append(names, "foo")
names = append(names, "bar")
fmt.Println(names)
}
Yields:
>> [foo bar]
If you are into the mechanics of it, here is a nice blog post.
Stick with what you are doing. The 100 DOES NOT prevent the slice from having more the 100 elements
names := make([]string, 0, 100)
names = append(names, "Jack")
names = append(names, "Jacob")
I would strongly suggest to set the capacity of the slice if you have rough estimates of number of elements and ALWAYS use append to add elements to the slice. You don't have to worry about the exceeding your estimate as append WILL create new array to fit the added elements.
names := make([]string)
The above case your array has 0 capacity, and append will cause the underlying array to be created again and again. This will have impact in performance. You should avoid this. If you worry about taking up more space in the memory you might consider creating slice of pointer to a type
objList := make([]*MyStructType, 0, 100)
You can consider setting an initial length, instead of '0', in addition of your capacity (100, meaning at most 100 elements can be added).
See "Arrays, slices (and strings): The mechanics of 'append'"
allocation.
We could use the new built-in function to allocate a bigger array and then slice the result, but it is simpler to use the make built-in function instead.
It allocates a new array and creates a slice header to describe it, all at once. The make function takes three arguments: the type of the slice, its initial length, and its capacity, which is the length of the array that make allocates to hold the slice data
The idea is to avoid append() to have to grow the slice too soon, especially if you know you will receive at least n elements.

Are args and args[..] the same?

I'm reading optparse.coffee, and confused with the following line:
args = args[..]
What does that line do?
From the fine manual:
Array Slicing and Splicing with Ranges
Ranges can also be used to extract slices of arrays. With two dots (3..6), the range is inclusive (3, 4, 5, 6); with three dots (3...6), the range excludes the end (3, 4, 5). Slices indices have useful defaults. An omitted first index defaults to zero and an omitted second index defaults to the size of the array.
So saying array[..] is shorthand for:
len = array.length
array[0 .. len]
and that just makes a shallow copy of array. That means that args = args[..] just makes a local shallow copy of args so that args can be manipulated and changed without altering the original array that was passed in and you can store references to the array without the function's caller being able to accidentally alter your array through the original args reference that was passed to the function.
Consider this simplified example:
f = (args) -> args = args[..]
that becomes this JavaScript:
var f;
f = function(args) {
return args = args.slice(0);
};
And Array#slice:
Returns a shallow copy of a portion of an array.
[...]
If end is omitted, slice extracts to the end of the sequence.
So saying array.slice(n) returns a shallow copy of array starting at index n and going to the end of array and since arrays are indexed starting at zero, array.slice(0) makes a shallow copy of the entire array.

How to delete an element from an array in D

Concatenating an element x to an array items is easy in D, it's as if it were an array list:
arr ~= x;
but how do I remove an element at index i from items?
(Caveat: If I remove an element and then add a new element, the array must not be reallocated. So a simple slice won't work.)
Update:
Based on CyberShadow's answer about using assumeSafeAppend, I wrote this code:
static void removeAt(T)(ref T[] arr, size_t index)
{
foreach (i, ref item; arr[index .. $ - 1])
item = arr[i + 1];
arr = arr[0 .. $ - 1];
arr.assumeSafeAppend();
}
However, the problem happens when you have something like:
auto superArr = [0, 1, 2, 3, 4]; //Must not be modified
auto arr = superArr[0 .. $ - 1];
writeln(superArr);
arr.removeAt(0); //Should copy the slice and modify the copy
writeln(superArr); //but obviously doesn't
The base array of slice should not be modified if an element is removed from the slice; instead, the slice needs to be copied.
But I have no way of knowing if an array is a slice of a bigger array... so that doesn't work.
Any suggestions?
Copying my answer on digitalmars.D (thanks for forwarding):
As has been mentioned, std.algorithm.remove can be of help. You may want to look at three of its capabilities in particular: (a) remove multiple offsets in one pass, e.g. remove(a, 0, 4) removes the first and fifth element, (b) you can remove subranges, e.g. remove(a, tuple(1, 3)) removes the second through fourth element, and (c) if you don't care about the order in which elements are left after removal you may want to look into unstable remove, which does considerably less work.
Andrei
(Caveat: If I remove an element and then add a new element, the array must not be reallocated. So a simple slice won't work.)
The assumeSafeAppend function will tell the runtime not to reallocate the array when appending to it (i.e. it is an affirmation from the user that there aren't other slices which might be stomped by an append).
remove from std.algorithm does an in-place remove. If you're using std.container, there's also Array.linearRemove.
Well if order is of no importance you can copy the last element to the location of removal then reduce the array length by one.
If you just want to remove the first or last elements use slices:
array = array [1..$]
array = array [0..$-1]
Or a general way which works for a middle one as well:
array = array [0..unlucky] ~ array [unlucky+1..$]
If the elements aren't basic elements such as structs, floats, ints then arrays are implicitly arrays of pointers and this is an efficient operation.
There's no automated way of doing this, you'll have to shuffle the array items along, reset .length and then catenate.

Resources