This question already has answers here:
How do I reverse a slice in go?
(6 answers)
Closed 11 months ago.
I don't understand what is wrong with the below implementation, I had a look at sort.StringSlice and it looks the same.
type RevStr []string
func(s RevStr) Len() int { return len(s) }
func(s RevStr) Less(i, j int) bool { return s[i] < s[j] }
func(s RevStr) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func Reverse(input string) string {
rs := RevStr(strings.Split(input, " "))
sort.Reverse(rs)
return strings.Join(rs, " ")
}
sort.Reverse doesn't sort the data, but rather returns a new sort.Interface that will sort the data in reverse order. So you don't really need your own type:
func Reverse(input string) string {
s := strings.Split(input, " ")
sort.Sort(sort.Reverse(sort.StringSlice(s)))
return strings.Join(s, " ")
}
Playground: http://play.golang.org/p/w49FDCEHo3.
EDIT: If you just need to reverse a slice of strings, just do:
func reverse(ss []string) {
last := len(ss) - 1
for i := 0; i < len(ss)/2; i++ {
ss[i], ss[last-i] = ss[last-i], ss[i]
}
}
Playground: http://play.golang.org/p/UptIRFV_SI
Nothing is wrong with your RevStr type (though you could just use sort.StringSlice). You're not calling sort.Sort on the reversed implementation:
https://golang.org/pkg/sort/#example_Reverse
package main
import (
"fmt"
"sort"
)
func main() {
s := []int{5, 2, 6, 3, 1, 4} // unsorted
sort.Sort(sort.Reverse(sort.IntSlice(s)))
fmt.Println(s)
}
Although #Ainar-G has provided a way to reverse a slice of strings, I think it's nicer to use two variables in for loop to reverse. But it's only my personal opinion, a matter of style :)
func reverse(s []string) []string {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
return s
}
Playground link with example of usage: http://play.golang.org/p/v1Cy61NFv1
A one-liner solution (using a lambda):
Given:
myStrings := []string{"apple", "banana", "cherry"}
Sort (in reverse order) with:
sort.Slice(myStrings, func(i, j int) bool { return myStrings[i] > myStrings[j]})
Playground Example:
https://play.golang.org/p/WZabAZTizHG
More simple way, without using built-in sorting feature :
func reverse(s []string) []string {
for i := len(s) - 1; i >= 0; i-- {
result = append(result, s[i])
}
return s
}
func reverseStr(data []string) []string {
m := len(data) - 1
var out = []string{}
for i := m; i >= 0; i-- {
out = append(out, data[i])
}
return out
}
Related
Please help me implement bubble sort.It works fine if I call it with a hardcoded slice from the main() but if I call it with dynamic input from Scan it breaks
here is my code so far:
package main
import "fmt"
func main() {
fmt.Println("Enter a maximum of 10 numbers: ")
var inputs int
fmt.Scanln(&inputs)
inputSlice := make([]int, inputs)
BubbleSort(inputSlice)
fmt.Println(inputSlice)
}
func BubbleSort(input []int) {
for i := 0; i < len(input)-1; i++ {
for j := 0; j < len(input)-i-1; j++ {
Swap(input, j)
}
}
}
func Swap(input []int, j int) {
if input[j] > input[j+1] {
input[j], input[j+1] = input[j+1], input[j]
}
}
terminal:
coder:~/project$ go run bubblesort.go
Enter a maximum of 10 numbers:
12 24 54 65 11
coder:~/project$ 4 54 65 11
bash: 4: command not found
Do a little debugging by adding print lines in between your codes and see what's actually happening, you were just reading input the wrong way from command line
After Taking Reference from this link as posted above in comments by Steffen Ullrich
View In Go Playground
package main
import "fmt"
func main() {
fmt.Println(`Enter the number of integers`)
var n int
if m, err := Scan(&n); m != 1 {
panic(err)
}
fmt.Println(`Enter the integers`)
inputSlice := make([]int, n)
ReadN(inputSlice, 0, n)
//Your Input Printing Out
fmt.Println(inputSlice)
//Calling Function
BubbleSort(inputSlice)
//Output
fmt.Println(inputSlice)
}
func BubbleSort(input []int) {
for i := 0; i < len(input)-1; i++ {
for j := 0; j < len(input)-i-1; j++ {
Swap(input, j)
}
}
}
func Swap(input []int, j int) {
if input[j] > input[j+1] {
input[j], input[j+1] = input[j+1], input[j]
}
}
//Additional Functions
func ReadN(all []int, i, n int) {
if n == 0 {
return
}
if m, err := Scan(&all[i]); m != 1 {
panic(err)
}
ReadN(all, i+1, n-1)
}
func Scan(a *int) (int, error) {
return fmt.Scan(a)
}
I am trying to solve a puzzle to practice my Go. But, I am a little stuck and the error is not very helpful.
./prog.go:22:23: cannot assign to v[j]
./prog.go:22:23: cannot assign to v[wLen - 1 - j]
func SpinWords(str string) string {
ws := strings.Split(str, " ")
for i := 0; i < len(ws); i++ {
v := ws[i]
wLen := len(v)
if wLen > 4 {
for j := 0; j < wLen/2; j++ {
v[j], v[wLen-1-j] = v[wLen-1-j], v[j]
}
ws[i] = v
}
}
return strings.Join(ws, " ")
}
Almost working code here: https://play.golang.org/p/j9BYk642bFa
You can't assign to elements of v because v is a string and strings are immutable. You can convert the string to a []byte first, and then work with the elements of it, but it is not safe if your strings contain multi-byte characters.
v:=[]byte(ws[i])
Or you can convert the string to a []rune and work with it:
v:=[]rune(ws[i])
Then you can assign to elements of v, and when you're done, convert it back to a string:
str:=string(v)
If you want to performed the action then you have to convert word from string to []rune
This code works :)
package main
import (
"fmt"
"strings"
)
func main() {
result := SpinWords("Welcome to the jungle we got fun and games")
fmt.Println(result)
}
func SpinWords(str string) string {
ws := strings.Split(str, " ")
for i := 0; i < len(ws); i++ {
v := ws[i]
wLen := len(v)
if wLen > 4 {
vinrune := []rune(v)
for j := 0; j < wLen/2; j++ {
vinrune[j], vinrune[wLen-1-j] = vinrune[wLen-1-j], vinrune[j]
}
v = string(vinrune)
ws[i] = v
}
}
return strings.Join(ws, " ")
}
I'm writing Go application using Go 1.7rc3.
I have a slice of uint64 (var dirRange []uint64) that I want to sort.
The sort package has a function sort.Ints() but it requires []int and I have []uint64.
What do I do? Can I type cast the all slice?
As of version 1.8, you can use the simpler function sort.Slice. In your case, it would be something like the following:
sort.Slice(dirRange, func(i, j int) bool { return dirRange[i] < dirRange[j] })
This avoids having to define any type just for the sorting.
You can define sort.Interface on your dirRange, which can be a type aliasing []uint64:
type DirRange []uint64
func (a DirRange) Len() int { return len(a) }
func (a DirRange) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a DirRange) Less(i, j int) bool { return a[i] < a[j] }
func main() {
dirRange := DirRange{2, 5, 7, 1, 9, 4}
sort.Sort(dirRange)
fmt.Println(dirRange)
}
Output:
[1 2 4 5 7 9]
This way you can avoid casting and work directly with your array. Since the underlying type is a slice []uint64, you can still use general slice operations. For example:
dirRange := make(DirRange, 10)
dirRange = append(dirRange, 2)
You can provide a type alias for []uint64, add the standard "boilerplate" sorting methods to implement sort.interface (Len, Swap, and Less - https://golang.org/pkg/sort/#Interface); then either create an instance of the new type or typecast an existing slice []uint64 into the new type, as done in the following example (also https://play.golang.org/p/BbB3L9TmBI):
package main
import (
"fmt"
"sort"
)
type uint64arr []uint64
func (a uint64arr) Len() int { return len(a) }
func (a uint64arr) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a uint64arr) Less(i, j int) bool { return a[i] < a[j] }
func (a uint64arr) String() (s string) {
sep := "" // for printing separating commas
for _, el := range a {
s += sep
sep = ", "
s += fmt.Sprintf("%d", el)
}
return
}
func main() {
dirRange := []uint64{3, 2, 400000}
arr := uint64arr(dirRange)
sort.Sort(arr)
fmt.Printf("%s\n", arr)
fmt.Printf("%#v\n", dirRange)
}
The output is:
2, 3, 400000
[]uint64{0x2, 0x3, 0x61a80}
showing that both arrays are sorted since the second one is a typecasted alias for the original.
There is no wrapper function, you need to use the Slice function, and this is an example:
arr := []uint64{5, 0, 3, 2, 1, 6}
sort.Slice(arr, func(i, j int) bool { return arr[i] < arr[j] })
I want the strings to be sorted alphabetically with control over whether "A" comes before "a".
In the Less() function using strings.ToLower() doesn't achieve this. Sometimes "A" comes before "a", and sometimes after.
instead of comparing the entire string using strings.ToLower, compare the individual runes.
https://play.golang.org/p/RUMlmrb7C3g
type ByCase []string
func (s ByCase) Len() int { return len(s) }
func (s ByCase) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ByCase) Less(i, j int) bool {
iRunes := []rune(s[i])
jRunes := []rune(s[j])
max := len(iRunes)
if max > len(jRunes) {
max = len(jRunes)
}
for idx := 0; idx < max; idx++ {
ir := iRunes[idx]
jr := jRunes[idx]
lir := unicode.ToLower(ir)
ljr := unicode.ToLower(jr)
if lir != ljr {
return lir < ljr
}
// the lowercase runes are the same, so compare the original
if ir != jr {
return ir < jr
}
}
// If the strings are the same up to the length of the shortest string,
// the shorter string comes first
return len(iRunes) < len(jRunes)
}
This may be a solution:
package main
import (
"strings"
"sort"
"fmt"
)
var listOfStrings []string = []string{
"mars bar",
"milk-duds",
"Mars bar",
"milk",
"milky-way",
"Milk",
"Milky-way",
"mars",
}
type Alphabetic []string
func (list Alphabetic) Len() int { return len(list) }
func (list Alphabetic) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
func (list Alphabetic) Less(i, j int) bool {
var si string = list[i]
var sj string = list[j]
var si_lower = strings.ToLower(si)
var sj_lower = strings.ToLower(sj)
if si_lower == sj_lower {
return si < sj
}
return si_lower < sj_lower
}
func main() {
fmt.Println("UNSORTED")
printStrings(listOfStrings)
sort.Sort(Alphabetic(listOfStrings))
fmt.Println()
fmt.Println("SORTED ALPHABETICALLY")
printStrings(listOfStrings)
}
func printStrings(slice []string) {
for i := 0; i < len(slice); i++ {
fmt.Println(slice[i])
}
}
Here's the output:
UNSORTED
mars bar
milk-duds
Mars bar
milk
milky-way
Milk
Milky-way
mars
SORTED ALPHABETICALLY
mars
Mars bar
mars bar
Milk
milk
milk-duds
Milky-way
milky-way
Heres a Unicode friendly method that utilizes strings.Map:
package main
import (
"fmt"
"sort"
"strings"
"unicode"
)
type slice struct { sort.StringSlice }
func (s slice) Less(d, e int) bool {
t := strings.Map(unicode.ToUpper, s.StringSlice[d])
u := strings.Map(unicode.ToUpper, s.StringSlice[e])
return t < u
}
func main() {
a := slice{
sort.StringSlice{"a", "b", "A", "B"},
}
sort.Sort(a)
fmt.Println(a.StringSlice) // [a A b B]
}
https://golang.org/pkg/strings#Map
How do I reverse an arbitrary slice ([]interface{}) in Go? I'd rather not have to write Less and Swap to use sort.Reverse. Is there a simple, builtin way to do this?
The standard library does not have a built-in function for reversing a slice. Use a for loop to reverse a slice:
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
Use type parameters to write a generic reverse function in Go 1.18 or later:
func reverse[S ~[]E, E any](s S) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
Use reflect.Swapper to write a function that works with arbitrary slice types in Go version 1.8 or later:
func reverse(s interface{}) {
n := reflect.ValueOf(s).Len()
swap := reflect.Swapper(s)
for i, j := 0, n-1; i < j; i, j = i+1, j-1 {
swap(i, j)
}
}
Run the code on the Go playground.
The functions in this answer reverse the slice inplace. If you do not want to modify the original slice, copy the slice before reversing the slice.
Here's another possible way to reverse generic slice (go 1.18)
// You can edit this code!
// Click here and start typing.
package main
import (
"fmt"
"sort"
)
func main() {
nums := []int64{10, 5, 15, 20, 1, 100, -1}
ReverseSlice(nums)
fmt.Println(nums)
strs := []string{"hello", "world"}
ReverseSlice(strs)
fmt.Println(strs)
runes := []rune{'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'}
ReverseSlice(runes)
for _, r := range runes {
fmt.Print(string(r), " ")
}
}
func ReverseSlice[T comparable](s []T) {
sort.SliceStable(s, func(i, j int) bool {
return i > j
})
}
Running the program above should output:
[-1 100 1 20 15 5 10]
[world hello]
d l r o w o l l e h
Program exited.
go playground
This will return a reversed slice without modifying the original slice.
Algorithm used from official wiki page: https://github.com/golang/go/wiki/SliceTricks#reversing
func reverse(s []interface{}) []interface{} {
a := make([]interface{}, len(s))
copy(a, s)
for i := len(a)/2 - 1; i >= 0; i-- {
opp := len(a) - 1 - i
a[i], a[opp] = a[opp], a[i]
}
return a
}
There are my code example, you can run it in playground
package main
import (
"fmt"
"reflect"
"errors"
)
func ReverseSlice(data interface{}) {
value := reflect.ValueOf(data)
if value.Kind() != reflect.Slice {
panic(errors.New("data must be a slice type"))
}
valueLen := value.Len()
for i := 0; i <= int((valueLen-1)/2); i++ {
reverseIndex := valueLen - 1 - i
tmp := value.Index(reverseIndex).Interface()
value.Index(reverseIndex).Set(value.Index(i))
value.Index(i).Set(reflect.ValueOf(tmp))
}
}
func main() {
names := []string{"bob", "mary", "sally", "michael"}
ReverseSlice(names)
fmt.Println(names)
}
Here is the function I'm using with generics (go 1.18+). You can use it to reverse any kind of slice or even a string (using the split/join trick). It doesn't change the original slice.
package main
import (
"fmt"
"strings"
)
func Reverse[T any](original []T) (reversed []T) {
reversed = make([]T, len(original))
copy(reversed, original)
for i := len(reversed)/2 - 1; i >= 0; i-- {
tmp := len(reversed) - 1 - i
reversed[i], reversed[tmp] = reversed[tmp], reversed[i]
}
return
}
func main() {
a := []string{"a", "b", "c"}
fmt.Println(a, Reverse(a))
b := []uint{0, 1, 2}
fmt.Println(b, Reverse(b))
c := "abc"
fmt.Println(c, strings.Join(Reverse(strings.Split(c, "")), ""))
}
Better Go Playground
This generic slice reversal function should do it for you:
func ReverseSlice[T comparable](s []T) []T {
var r []T
for i := len(s) - 1; i >= 0; i-- {
r = append(r, s[i])
}
return r
}