Home > front end >  Package sort in go affects all slices
Package sort in go affects all slices

Time:10-20

I make a slice of strings in go. Then, I make two other slices. The first is unsorted original slice, and the second is sorted original slice. But, when I sort the second slice using package sort, the first slice is getting sorted as well. How can I sort only the second one?

og := []string{"go", "python", "java", "C  "}
unsorted :=og
sorted := og

sort.Strings(sorted)

fmt.Println("unsorted", unsorted)
fmt.Println("sorted", sorted)

Actual output:

unsorted [C   go java python]
sorted [C   go java python]

Expected output:

unsorted [go python java C  ]
sorted [C   go java python]

CodePudding user response:

So slices are sometimes referred to as reference types. You can read more about the differences between arrays and slices here, for example (first page I found).

What a slice basically is, as you can see from the source in the runtime package (slice.go file):

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

When you're assigning the slice to unsorted and the sorted variables, you're creating a copy of this underlying slice struct. You're essentially copying the pointer to the underlying array, which is being manipulated by sort.Strings(), hence both references to the slice will reflect these changes.

What you'll want to do is copy the slice into a new one to avoid seeing the order change a go playground snippet here.

For completeness sake:

og := []string{"go", "python", "java", "C  "}
unsorted := make([]string, len(og)) // create a new slice
copy(unsorted, og) // copy over values
sorted := og // this isn't a required line, you can just sort og
sort.Strings(sorted)
fmt.Printf("%#v\n%#v\n", unsorted, sorted)

Rather than using make and calling copy, you can simplify it as follows:

unsorted := append([]string{}, og...) // append to new slice == copy

CodePudding user response:

When you assign one slice to a another you get a shallow copy. They will both refer to the same underlying array of data.

If you want to modify one and keep the original, you would need to copy the content of the slice, then modify it.

package main

import (
    "fmt"
    "sort"
)

func copySlice(slice []string) []string {
    newSlice := make([]string, len(slice))
    copy(newSlice, slice)
    return newSlice
}

func main() {
    og := []string{"go", "python", "java", "C  "}
    unsorted := copySlice(og)
    sorted := copySlice(og)

    sort.Strings(sorted)

    fmt.Println("unsorted", unsorted)
    fmt.Println("sorted", sorted)
}
  • Related