0

I just want a function that having a slice of a struct type "t", returns the returns the element I'm looking for and the remaining, I tried with the partial solution for my problem like pointed out here: Delete element in a slice But for a weird reason, it does not work as expected https://play.golang.org/p/tvJwkF5c_tj

    func main() {
    var names = []string{"john", "julio", "pepito","carlos"}
    fmt.Println(getMe("john", names))
}
func getMe(me string, names []string) (string, []string, bool) {
    for i := range names {
        if names[i] == me {
            return names[i], append(names[:i], names[i+1:]...), true
        }
    }
    return "", nil, false
}

but the result gives me:

julio [julio pepito carlos] true

UPDATE: https://play.golang.org/p/1xbu01rOiMg Taking the answer from @Ullaakut If I do: append(names[:i], names[i+1:]...), it changes the original slice, so this does not work for me, I do not want my slice to change, because I will be using it later on

Community
  • 1
  • 1
John Balvin Arias
  • 2,632
  • 3
  • 26
  • 41

1 Answers1

2

Simply use the range to get both the value and the index, instead of accessing the value by using the index.

package main

import (
    "fmt"
)

func main() {
    var names = []string{"john", "julio", "pepito", "carlos"}
    name, newNames, _ := getMe("john", names)

    fmt.Println("extracted name:\t\t\t\t", name)
    fmt.Println("new slice without extracted name:\t", newNames)
    fmt.Println("old slice still intact:\t\t\t", names)
}

func getMe(me string, names []string) (string, []string, bool) {
    var newSlice []string

    for i := 0; i < len(names); i++ {
        if names[i] == me {
            newSlice = append(newSlice, names[:i]...)
            newSlice = append(newSlice, names[i+1:]...)
            return names[i], newSlice, true
        }
    }

    return "", nil, false
}

Outputs

extracted name:                        john
new slice without extracted name:      [julio pepito carlos]
old slice still intact:                [john julio pepito carlos]

See playground example

Edit after request for a faster version: Using the manual for instead of the range loop is much faster. Since you need to create a new slice without the element, it's necessary to build a new slice within the function, which is always going to take some processing power.

Ullaakut
  • 3,554
  • 2
  • 19
  • 34
  • Glad I could help :) – Ullaakut Sep 11 '18 at 21:34
  • Hi, I just encounter another problem with the solution, see my updated question – John Balvin Arias Sep 12 '18 at 17:00
  • Yes it changes the original slice, and that is why it didn't work originally, you were returning the first element of your slice and then deleting it, which in turn made it so that you returned the first element of your old slice :) I will update my answer. – Ullaakut Sep 12 '18 at 17:06
  • wouldn't that be expensive if I do it multiple times? – John Balvin Arias Sep 12 '18 at 17:14
  • I can write a less expensive version if you want, sure – Ullaakut Sep 12 '18 at 17:17
  • Updated the code & link to the playground, and explained what are the speed improvements. Feel free to benchmark it, it should be quite faster than the previous version, but the main bottleneck stays the creation of a new slice, which can only be solved by changing the way you are architecturing your code to not require the creation of a second slice :/ Let me know if this is good enough for you and feel free to validate the answer if so :) – Ullaakut Sep 12 '18 at 17:28
  • It does not work, it continues to change the original slice – John Balvin Arias Sep 12 '18 at 17:34
  • Yep my bad, forgot that calling `append()` on `names` would modify it. The only obvious option I see then is to append it to the newSlice, updated the code. – Ullaakut Sep 12 '18 at 20:21
  • 1
    At the end it's the same as the other one :D, but anyway I'll stick with that one, thanks! – John Balvin Arias Sep 13 '18 at 02:08