fmt.Println("Enter position to delete::")
fmt.Scanln(&pos)
new_arr := make([]int, (len(arr) - 1))
k := 0
for i := 0; i < (len(arr) - 1); {
if i != pos {
new_arr[i] = arr[k]
k++
i++
} else {
k++
}
}
for i := 0; i < (len(arr) - 1); i++ {
fmt.Println(new_arr[i])
}
Używam tego polecenia, aby usunąć element z plasterka, ale nie działa, proszę zasugerować.
Odpowiedzi:
Porządek ma znaczenie
Jeśli chcesz zachować porządek w tablicy, musisz przesunąć wszystkie elementy po prawej stronie kasującego indeksu o jeden w lewo. Miejmy nadzieję, że da się to łatwo zrobić w Golang:
func remove(slice []int, s int) []int { return append(slice[:s], slice[s+1:]...) }
Jest to jednak nieefektywne, ponieważ może skończyć się przeniesieniem wszystkich elementów, co jest kosztowne.
Porządek nie jest ważny
Jeśli nie zależy Ci na kolejności, masz znacznie szybszą możliwość zamiany elementu do usunięcia z tym na końcu wycinka, a następnie zwrócenia n-1 pierwszych elementów:
func remove(s []int, i int) []int { s[len(s)-1], s[i] = s[i], s[len(s)-1] return s[:len(s)-1] }
W przypadku metody reslicingu opróżnienie tablicy 1 000 000 elementów zajmuje 224 s, przy tej zajmuje tylko 0,06 ns. Podejrzewam, że wewnętrznie go zmienia tylko długość plastra, bez modyfikowania go.
Edytuj 1
Szybkie notatki na podstawie poniższych komentarzy (dzięki!).
Ponieważ celem jest usunięcie elementu, gdy kolejność nie ma znaczenia, potrzebna jest pojedyncza zamiana, druga zostanie zmarnowana:
func remove(s []int, i int) []int { s[i] = s[len(s)-1] // We do not need to put s[i] at the end, as it will be discarded anyway return s[:len(s)-1] }
Również ta odpowiedź nie sprawdza granic . Oczekuje prawidłowego indeksu jako danych wejściowych. Oznacza to, że ujemne wartości lub wskaźniki większe lub równe len (s) spowodują panikę. Wycinki i tablice są indeksowane 0, usunięcie n-tego elementu tablicy oznacza dostarczenie danych wejściowych n-1 . Aby usunąć pierwszy element, wywołaj remove (s, 0) , aby usunąć drugi, wywołanie remove (s, 1) itd.
źródło
s[i] = s[len(s)-1]; return s[:len(s)-1]
to wystarczy.s[i] = s[len(s)-1]
zdecydowanie kopiuje ostatni element do elementu pod indeksemi
. Następniereturn s[:len(s)-1]
zwraca wycinek bez ostatniego elementu. Tam są dwa stwierdzenia.s[len(s)-1], s[i] = 0, s[len(s)-1]
. Zwłaszcza jeśli pracujesz z tablicami nieprymitywnymi. Jeśli masz do czegoś wskaźniki, lepiej jest utworzyć element, który chcesz usunąćnil
przed wycięciem, aby nie mieć wskaźników w podstawowej tablicy. Ta odpowiedź bardzo dobrze wyjaśnia, dlaczego . W skrócie: po przesunięciu ostatniego elementu w miejsce usuniętego elementu wyzeruj ostatni element przed cięciem.Usuń jeden element z Plasterka (nazywa się to „ponownym pokrojeniem”):
package main import ( "fmt" ) func RemoveIndex(s []int, index int) []int { return append(s[:index], s[index+1:]...) } func main() { all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} fmt.Println(all) //[0 1 2 3 4 5 6 7 8 9] all = RemoveIndex(all, 5) fmt.Println(all) //[0 1 2 3 4 6 7 8 9] }
źródło
2019/09/28 19:46:25 http: panic serving 192.168.1.3:52817: runtime error: slice bounds out of range [7:5] goroutine 7 [running]:
panic
gdyby indeks był ostatnim elementem w WycinkuDrobny punkt (kod golfowy), ale w przypadku, gdy kolejność nie ma znaczenia, nie musisz zamieniać wartości. Po prostu nadpisz usuwaną pozycję tablicy duplikatem ostatniej pozycji, a następnie zwróć obciętą tablicę.
func remove(s []int, i int) []int { s[i] = s[len(s)-1] return s[:len(s)-1] }
Ten sam wynik.
źródło
s[i] = s[0]
, a następnie zwrócenie tablicy zawierającej tylko ostatnie n-1 elementów.return s[1:]
s[1:]
porównaniu zs[:len(s)-1]
tym, że późniejszy będzie działał znacznie lepiej, jeśli kawałek później zostanie edytowany lub usunięteappend
zostaną wymieszane zappend
s. Ta ostatnia zachowuje pojemność plastra tam, gdzie ta pierwsza nie.To trochę dziwne, ale większość odpowiedzi tutaj jest niebezpieczna i przesłania to, co faktycznie robią. Patrząc na pierwotne pytanie, które zostało zadane na temat usuwania elementu z plasterka, kopia plastra jest tworzona, a następnie jest wypełniana. Gwarantuje to, że gdy plasterki są przekazywane wokół programu, nie wprowadzasz subtelnych błędów.
Oto kod porównujący odpowiedzi użytkowników w tym wątku i oryginalny post. Oto plac zabaw, w którym można bawić się tym kodem.
Usuwanie na podstawie dołączania
package main import ( "fmt" ) func RemoveIndex(s []int, index int) []int { return append(s[:index], s[index+1:]...) } func main() { all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9] removeIndex := RemoveIndex(all, 5) fmt.Println("all: ", all) //[0 1 2 3 4 6 7 8 9 9] fmt.Println("removeIndex: ", removeIndex) //[0 1 2 3 4 6 7 8 9] removeIndex[0] = 999 fmt.Println("all: ", all) //[999 1 2 3 4 6 7 9 9] fmt.Println("removeIndex: ", removeIndex) //[999 1 2 3 4 6 7 8 9] }
W powyższym przykładzie możesz zobaczyć, jak tworzę wycinek i ręcznie wypełniam go numerami od 0 do 9. Następnie usuwamy indeks 5 ze wszystkich i przypisujemy go do usunięcia indeksu. Jednak kiedy idziemy teraz wydrukować wszystko, widzimy, że zostało to również zmodyfikowane. Dzieje się tak, ponieważ plasterki są wskaźnikami do tablicy bazowej. Zapisanie go do
removeIndex
przyczyn, któreall
mają być również zmodyfikowane, z tą różnicą, żeall
jest dłuższy o jeden element, z którego nie można już dotrzećremoveIndex
. Następnie zmieniamy wartość wremoveIndex
i widzimy, że równieżall
zostaje zmodyfikowana. Efektywne przejście do bardziej szczegółowych informacji na ten temat.Poniższy przykład, którym nie będę się zajmował, ale robi to samo dla naszych celów. I tylko pokazuje, że używanie kopiowania nie jest inne.
package main import ( "fmt" ) func RemoveCopy(slice []int, i int) []int { copy(slice[i:], slice[i+1:]) return slice[:len(slice)-1] } func main() { all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9] removeCopy := RemoveCopy(all, 5) fmt.Println("all: ", all) //[0 1 2 3 4 6 7 8 9 9] fmt.Println("removeCopy: ", removeCopy) //[0 1 2 3 4 6 7 8 9] removeCopy[0] = 999 fmt.Println("all: ", all) //[99 1 2 3 4 6 7 9 9] fmt.Println("removeCopy: ", removeCopy) //[999 1 2 3 4 6 7 8 9] }
Na pytania oryginalna odpowiedź
Patrząc na oryginalne pytanie, nie modyfikuje plastra, z którego usuwa element. Jak dotąd oryginalna odpowiedź w tym wątku była jak dotąd najlepsza dla większości osób odwiedzających tę stronę.
package main import ( "fmt" ) func OriginalRemoveIndex(arr []int, pos int) []int { new_arr := make([]int, (len(arr) - 1)) k := 0 for i := 0; i < (len(arr) - 1); { if i != pos { new_arr[i] = arr[k] k++ } else { k++ } i++ } return new_arr } func main() { all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9] originalRemove := OriginalRemoveIndex(all, 5) fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9] fmt.Println("originalRemove: ", originalRemove) //[0 1 2 3 4 6 7 8 9] originalRemove[0] = 999 fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9] fmt.Println("originalRemove: ", originalRemove) //[999 1 2 3 4 6 7 8 9] }
Jak widać, ten wynik działa zgodnie z oczekiwaniami większości ludzi i prawdopodobnie tym, czego większość ludzi chce. Modyfikacja
originalRemove
nie powoduje zmian,all
a operacja usunięcia indeksu i przypisanie go również nie powoduje zmian! Fantastyczny!Ten kod jest jednak trochę za długi, więc powyższy można zmienić na ten.
Prawidłowa odpowiedź
package main import ( "fmt" ) func RemoveIndex(s []int, index int) []int { ret := make([]int, 0) ret = append(ret, s[:index]...) return append(ret, s[index+1:]...) } func main() { all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9] removeIndex := RemoveIndex(all, 5) fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9] fmt.Println("removeIndex: ", removeIndex) //[0 1 2 3 4 6 7 8 9] removeIndex[0] = 999 fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 9 9] fmt.Println("removeIndex: ", removeIndex) //[999 1 2 3 4 6 7 8 9] }
Prawie identyczne z oryginalnym rozwiązaniem do usuwania indeksu, jednak przed powrotem tworzymy nowy wycinek do dołączenia.
źródło
all
jest również zmieniany później,removeIndex := RemoveIndex(all, 5)
ponieważ funkcja append ponownie wykorzystuje tę samą podstawową tablicę, jeśli ma wystarczającą pojemność (usunięcie elementu oczywiście nie wymaga większej pojemności). I odwrotnie, jeśli dodamy elementy i przypiszemy doremoveIndex
, append przydzieli nową tablicę iall
nie zmieni się.Z książki The Go Programming Language
źródło
W ten sposób możesz usunąć z kawałka w idiomatyczny sposób . Nie musisz budować funkcji, która jest wbudowana w append. Wypróbuj tutaj https://play.golang.org/p/QMXn9-6gU5P
z := []int{9, 8, 7, 6, 5, 3, 2, 1, 0} fmt.Println(z) //will print Answer [9 8 7 6 5 3 2 1 0] z = append(z[:2], z[4:]...) fmt.Println(z) //will print Answer [9 8 5 3 2 1 0]
źródło
Podejmuję poniższe podejście, aby usunąć element w kawałku. To pomaga w czytelności dla innych. A także niezmienny.
func remove(items []string, item string) []string { newitems := []string{} for _, i := range items { if i != item { newitems = append(newitems, i) } } return newitems }
źródło
Znajdź drogę tutaj bez przeprowadzki.
a := []string{"A", "B", "C", "D", "E"} i := 2 // Remove the element at index i from a. a[i] = a[len(a)-1] // Copy last element to index i. a[len(a)-1] = "" // Erase last element (write zero value). a = a[:len(a)-1] // Truncate slice. fmt.Println(a) // [A B E D]
a := []string{"A", "B", "C", "D", "E"} i := 2 // Remove the element at index i from a. copy(a[i:], a[i+1:]) // Shift a[i+1:] left one index. a[len(a)-1] = "" // Erase last element (write zero value). a = a[:len(a)-1] // Truncate slice. fmt.Println(a) // [A B D E]
źródło
Najlepszym sposobem na to jest użycie funkcji append:
package main import ( "fmt" ) func main() { x := []int{4, 5, 6, 7, 88} fmt.Println(x) x = append(x[:2], x[4:]...)//deletes 6 and 7 fmt.Println(x) }
https://play.golang.org/p/-EEFCsqse4u
źródło
Może możesz wypróbować tę metodę:
// DelEleInSlice delete an element from slice by index // - arr: the reference of slice // - index: the index of element will be deleted func DelEleInSlice(arr interface{}, index int) { vField := reflect.ValueOf(arr) value := vField.Elem() if value.Kind() == reflect.Slice || value.Kind() == reflect.Array { result := reflect.AppendSlice(value.Slice(0, index), value.Slice(index+1, value.Len())) value.Set(result) } }
Stosowanie:
arrInt := []int{0, 1, 2, 3, 4, 5} arrStr := []string{"0", "1", "2", "3", "4", "5"} DelEleInSlice(&arrInt, 3) DelEleInSlice(&arrStr, 4) fmt.Println(arrInt) fmt.Println(arrStr)
Wynik:
0, 1, 2, 4, 5 "0", "1", "2", "3", "5"
źródło
Może ten kod pomoże.
Usuwa element o podanym indeksie.
Pobiera tablicę i indeks do usunięcia i zwraca nową tablicę, podobnie jak funkcja dołączania.
func deleteItem(arr []int, index int) []int{ if index < 0 || index >= len(arr){ return []int{-1} } for i := index; i < len(arr) -1; i++{ arr[i] = arr[i + 1] } return arr[:len(arr)-1] }
Tutaj możesz pobawić się kodem: https://play.golang.org/p/aX1Qj40uTVs
źródło
Nie musisz sprawdzać każdego elementu, chyba że zależy Ci na zawartości i możesz użyć dołączania plasterków. Wypróbuj to
pos := 0 arr := []int{1, 2, 3, 4, 5, 6, 7, 9} fmt.Println("input your position") fmt.Scanln(&pos) /* you need to check if negative input as well */ if (pos < len(arr)){ arr = append(arr[:pos], arr[pos+1:]...) } else { fmt.Println("position invalid") }
źródło
źródło
oto przykład placu zabaw ze wskazówkami. https://play.golang.org/p/uNpTKeCt0sH
package main import ( "fmt" ) type t struct { a int b string } func (tt *t) String() string{ return fmt.Sprintf("[%d %s]", tt.a, tt.b) } func remove(slice []*t, i int) []*t { copy(slice[i:], slice[i+1:]) return slice[:len(slice)-1] } func main() { a := []*t{&t{1, "a"}, &t{2, "b"}, &t{3, "c"}, &t{4, "d"}, &t{5, "e"}, &t{6, "f"}} k := a[3] a = remove(a, 3) fmt.Printf("%v || %v", a, k) }
źródło