Remove slice element and reinitialize slice [closed] - go

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
What is the correct way to remove an item from a slice in GO?
Also, what is the correct way to reinitialize a slice i.e. completely empty it but still keep it?

I believe you are misunderstanding the nature of a slice. A slice is like an ArrayList in Java. It is backed by a regular array and grows/shrinks on demand. Operations on a slice have the same performance characteristic as those you would expect on an ArrayList.
Your question(s) would make more sense if slices were the LinkedList equivalent. For that, look up Package list.
Nevertheless, here's how to do this. Most comes directly from SliceTricks, but I think it's good practice on SO to not refer to links and provide the answer right here.
Way to remove an item from a slice
This is something that you can do in any programming language, in O(1) time, if you don't care about order. If you care about order, this is not going to work.
The idea is to overwrite the item you want to remove with the last item in the slice, then reduce the size of the slice by one.
arr := []string{ "allo", "hello", "bye", "chao" }
// delete "bye"
deleteIdx := 2
lastIdx := len(arr) - 1
// arr = { "allo", "hello", "chao", "chao" }
arr[deleteIdx] = arr[lastIdx]
// arr = { "allo", "hello", "chao" } ... "chao"
arr = arr[:lastIdx - 1]
You can do that in a single step (SliceTricks):
arr[deleteIdx], arr = arr[len(arr)-1], arr[:len(arr) - 1]
However, like mentionned in the SliceTricks article, some type of values will not be garbage collected if you don't nil them, as the backing array behind the slice still holds a reference to them. The solution is to nil them while doing the operation.
arr[len(arr)-1], arr[deleteIdx], arr = nil, arr[len(arr)-1], arr[:len(arr)-1]
// ^ Setting the deleted index to nil ^
This is all, of course, if you don't care about preserving order. If you do care, you will need to copy everything after deleteIdx starting over deleteIdx, which is O(n). If you find yourself doing this, think if there isn't a better datastructure for your needs.
// Copy everything from [deleteIdx+1 .. n) onto [deleteIdx .. )
copy(arr[deleteIdx:], arr[deleteIdx+1:])
// arr[n - 1] and arr[n] have the same value (n = len(arr) - 1)
arr[len(arr)-1] = nil
// re-slice to reference only the n-1 elements
arr = arr[:len(arr)-1]
Way to reinitialize a slice i.e. completely empty it but keep it
You can reinitialize a slice by re-slicing all its items out
// Keep everything from [0 .. 0), which means keep nothing
arr = arr[:0]
But there's a problem in doing this : as stated above, the backing array of the slice will still reference to the original items that were in the slice. What you should do instead is create a new slice and let this one be garbage collected.

The answer is manyfold:
You must realize that there is no slice without backing array and if you talk about a slice you always have to think about the backing array too. Musing about this a bit leads to...
The second part of the question "reinitialize a slice i.e. completely empty it but still keep it" is very unclear. Do not think about slices in this way. a = a[:0] reslices a to zero length while keeping the backing array.
For everything else: Have a look at the "official" Slice Tricks https://code.google.com/p/go-wiki/wiki/SliceTricks

Related

Pointer operation isn't changing its reference within a slice

I just started learning go. I have a question about pointers.
In the code below, the following line in the code doesn't do what I expect:
last_line.Next_line = &line // slice doesn't change
I want the slice to be changed as well, not only the local variable last_line.
What am I doing wrong?
type Line struct {
Text string
Prev_line *Line
Next_line *Line
}
var (
lines []Line
last_line *Line
)
for i, record := range records {
var prev_line *Line = nil
text := record[0]
if i > 0 {
prev_line = &lines[i-1]
}
line := Line{
Text: text,
Prev_line: prev_line,
Next_line: nil}
if last_line != nil {
last_line.Next_line = &line // slice doesn't change
}
lines = append(lines, line)
last_line = &line
}
Your Line type is a fairly standard-looking doubly linked list. Your lines variable holds a slice of these objects. Combining these two is a bit unusual—not wrong, to be sure, just unusual. And, as Matt Oestreich notes in a comment, we don't know quite what is in records (just that range can be used on it and that after doing so, we can use record[0] to get to a single string value), so there might be better ways to deal with things.
If records itself is a slice or has a sensible len, we can allocate a slice of Line instances all at once, of the appropriate size:
lines = make([]Line, len(records))
Here is a sample on the Go Playground that does it this way.
If we can't really get a suitable len—e.g., if records is a channel whose length is not really relevant—then we might indeed want to allocate individual lines, but in this case, it may be more sensible to avoid keeping them as a slice in the first place. The doubly linked list alone will suffice.
Finally, if you really do want both a slice and this doubly linked list, note that using append may copy the slice's elements to a new, larger slice. If and when it does so, the pointers in any elements you set up earlier will point into the old, smaller slice. This is not invalid in terms of the language itself—those objects still exist and your pointers are keeping them "alive"—but it may not be what you intended at all. In this case, it makes more sense to set all the pointers at the end, after building up the lines slice, just as in the sample code I provided.
(The sample I wrote is deliberately slightly weird in a way that is likely to get your homework or test grade knocked down a bit, if this was an attempt to cheat on homework or a test. :-) )

How to write nice and clean Go package? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I try to implement Sparse sets from this article in Go and make it into a package. In early implementation, the API is clean and minimal with only exported type Sparse and exported method Insert, Delete, Has, Union, Intersection, Clear, and Len, pretty much only basic sets operation.
Later on, I want to add new functionality, sets that can reserve an element automatically (lets call it AutoSparse). If Sparse have Insert(k int) which insert k into sets, AutoSparse have Reserved() reserved an available element. If I have {0 1 2 4 5} in AutoSparse, when i call Reserve() it must add 3, not 6 so now it become {0 1 2 4 5 3}. Here's the implementation at playground.
As you can see, in order to maintain which element to added into sets, it doesn't add new field in the struct and I want to keep it like that.
My Question is how to add that new functionality to my package without adding new exported type AutoSparse to keep the API clean and minimal?
This is what i already try:
I can use interface to hide implementation but function signature is different, one use Insert(k int), the other use Reserve(), even if I use name Insert() it still different, or should I use Insert(k int) but didn't use k at all? it can but it's awkward.
I can't use the same struct to implement this because once you Use Reserve() to add element, you can't use Insert(k int) because it will messed up the reserved element, even Delete and Clear is different.
You can use k... int as parameter.
func (sparse Sparse) Insert(k... int) error {
if len(k) == 0 {
// first case
return nil
} else if len(k) == 1 {
// second case
return nil
} else {
return errors.New("Too many arguments")
}
}

Append a slice from a map value does not affect the map

mp := map[int][]int{}
slice := make([]int, 0, 1)
fmt.Printf("slice address:%p\n", slice)
mp[0] = slice
slice = append(slice, 1)
fmt.Println("after append")
fmt.Printf("slice address:%p\n", slice)
fmt.Println("slice:", slice)
fmt.Println("mp[0]:", mp[0])
fmt.Printf("mp[0] address:%p\n", mp[0])
output:
slice address:0xc042008f78
after append
slice address:0xc042008f78
slice: [1]
mp[0]: []
mp[0] address:0xc042008f78
The address of the slice does not change as its cap is large enough during append. So why the map value does not take effect?
As explained in Go Slices: usage and internals, two slices may point to the same memory location, but may have different len and cap attributes.
In Golang it is mentioned in blog on Go Slices: usage and internals
Slicing does not copy the slice's data. It creates a new slice value
that points to the original array. This makes slice operations as
efficient as manipulating array indices. Therefore, modifying the
elements (not the slice itself) of a re-slice modifies the elements of
the original slice:
slice = append(slice, 1)
So in the above case it is creating a new slice with pointing to the same original underlying array. That is the reason it is showing the same address.
To get the data of underlying array pointed by slice use reflect with unsafe:
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
data := *(*[1]int)(unsafe.Pointer(hdr.Data))
Working code on Playground
This is caused by the fact, that multiple slices can be backed by the same data but use different "sections" of the data. This means, that yes, an element is added to the data backing mp[0], but the length of the slice in mp is not changed. You can do that manually:
fmt.Println(mp[0][:1])
which does print [1].
You can grow any slice to it's capacity without changing the underlying data by using slice[:cap(slice)]. slice[:n] will panic if cap(slice) < n.
slice[n] on the other hand will panic when len(slice) <= n. I assume that the former is possible to allow the growing of slices without changing the underlying data (as far as that is possible). The latter, I would say, is "normal" behavior.
This also explains why mp[0][:2] panics, as cap(mp[0]) is 1.
For more details you might want to read this official blog post, as suggested by Flimzy.

golang why don't we have a set datastructure [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
The community reviewed whether to reopen this question 9 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I'm trying to solve "The go programming lanaguage" exercise #1.4 which requires me to have a set. I can create a set type but why doesn't the language come with one ? go, having come from google, where guava also originated, why didn't the language designers opt for adding support for fundamental data structures ? why force your users to create their own implementations for something so basic as a set ?
One reason is that it is easy to create a set from map:
s := map[int]bool{5: true, 2: true}
_, ok := s[6] // check for existence
s[8] = true // add element
delete(s, 2) // remove element
Union
s_union := map[int]bool{}
for k, _ := range s1{
s_union[k] = true
}
for k, _ := range s2{
s_union[k] = true
}
Intersection
s_intersection := map[int]bool{}
if len(s1) > len(s2) {
s1, s2 = s2, s1 // better to iterate over a shorter set
}
for k,_ := range s1 {
if s2[k] {
s_intersection[k] = true
}
}
It is not really that hard to implement all other set operations.
Partly, because Go doesn't have generics (so you would need one set-type for every type, or fall back on reflection, which is rather inefficient).
Partly, because if all you need is "add/remove individual elements to a set" and "relatively space-efficient", you can get a fair bit of that simply by using a map[yourtype]bool (and set the value to true for any element in the set) or, for more space efficiency, you can use an empty struct as the value and use _, present = the_setoid[key] to check for presence.
Like Vatine wrote: Since go lacks generics it would have to be part of the language and not the standard library. For that you would then have to pollute the language with keywords set, union, intersection, difference, subset...
The other reason is, that it's not clear at all what the "right" implementation of a set is:
There is a functional approach:
func IsInEvenNumbers(n int) bool {
if n % 2 == 0 {
return true
}
return false
}
This is a set of all even ints. It has a very efficient lookup and union, intersect, difference and subset can easily be done by functional composition.
Or you do a has-like approach like Dali showed.
A map does not have that problem, since you store something associated with the value.
Another possibility is to use bit sets, for which there is at least one package or you can use the built-in big package. In this case, basically you need to define a way to convert your object to an index.

How to remove the last element from a slice?

I've seen people say just create a new slice by appending the old one
*slc = append(*slc[:item], *slc[item+1:]...)
but what if you want to remove the last element in the slice?
If you try to replace i (the last element) with i+1, it returns an out of bounds error since there is no i+1.
You can use len() to find the length and re-slice using the index before the last element:
if len(slice) > 0 {
slice = slice[:len(slice)-1]
}
Click here to see it in the playground
TL;DR:
myslice = myslice[:len(myslice) - 1]
This will fail if myslice is zero sized.
Longer answer:
Slices are data structures that point to an underlying array and operations like slicing a slice use the same underlying array.
That means that if you slice a slice, the new slice will still be pointing to the same data as the original slice.
By doing the above, the last element will still be in the array, but you won't be able to reference it anymore.
If you reslice the slice to its original length you'll be able to reference the last object
If you have a really big slice and you want to also prune the underlying array to save memory, you probably wanna use "copy" to create a new slice with a smaller underlying array and let the old big slice get garbage collected.

Resources