गोलंग में एक स्लाइस से एक तत्व को कैसे हटाएं


111
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])
}

मैं एक स्लाइस से एक तत्व को हटाने के लिए इस कमांड का उपयोग कर रहा हूं लेकिन यह काम नहीं कर रहा है, कृपया सुझाव दें।


2
यह अच्छी तरह से पढ़ रहा है: blog.golang.org/go-slices-usage-and-internals
squiguy

जवाबों:


180

आदेश मायने रखता है

यदि आप अपने सरणी को क्रमबद्ध रखना चाहते हैं, तो आपको सभी तत्वों को एक-एक करके बाईं ओर इंडेक्स को दाईं ओर स्थानांतरित करना होगा। उम्मीद है, यह आसानी से गोलंग में किया जा सकता है:

func remove(slice []int, s int) []int {
    return append(slice[:s], slice[s+1:]...)
}

हालांकि, यह अक्षम है क्योंकि आप सभी तत्वों को स्थानांतरित करने के साथ समाप्त हो सकते हैं, जो महंगा है।

आदेश महत्वपूर्ण नहीं है

यदि आपको ऑर्डर करने की परवाह नहीं है, तो आपके पास स्लाइस के अंत में एक को हटाने के लिए तत्व को स्वैप करने की बहुत तेज़ संभावना है और फिर n-1 पहले तत्वों को लौटाएं:

func remove(s []int, i int) []int {
    s[len(s)-1], s[i] = s[i], s[len(s)-1]
    return s[:len(s)-1]
}

रेसिसलिंग विधि के साथ, 1 000 000 तत्वों की एक सरणी को खाली करने में 224 लगते हैं, इस एक के साथ यह केवल 0.06ns लेता है। मुझे संदेह है कि आंतरिक रूप से, केवल स्लाइस की लंबाई में परिवर्तन करें, इसे संशोधित किए बिना।

संपादित करें 1

नीचे टिप्पणी के आधार पर त्वरित नोट्स (उनके लिए धन्यवाद!)।

जैसा कि एक तत्व को हटाने का उद्देश्य है, जब आदेश में एक भी स्वैप की आवश्यकता नहीं होती है, तो दूसरा बर्बाद हो जाएगा:

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]
}

साथ ही, यह उत्तर सीमा-जाँच नहीं करता है । यह इनपुट के रूप में एक वैध सूचकांक की उम्मीद करता है। इसका मतलब यह है कि नकारात्मक मान या सूचकांक जो लेन (ओं) के लिए अधिक या बराबर हैं, इससे घबराहट होगी। स्लाइस और सरणियों को 0-अनुक्रमित किया जा रहा है, सरणी के n-वें तत्व को हटाने का तात्पर्य इनपुट n-1 प्रदान करना है । पहला तत्व निकालने के लिए, कॉल हटाने (एस, 0) , दूसरे को हटाने के लिए, कॉल निकालें (एस, 1) , और इसी तरह और आगे।


20
ऐसा लगता है कि यदि आप मूल स्लाइस के संरक्षण के बारे में परवाह नहीं करते हैं, तो आपको एक स्वैप की भी आवश्यकता नहीं होगी और यह s[i] = s[len(s)-1]; return s[:len(s)-1]पर्याप्त होगा।
ब्रैड पीबॉडी

@bgp यह केवल पॉपिंग (पिछले तत्व को हटाकर) स्लाइस का है, मूल प्रश्न में दिए गए इंडेक्स के तहत एक को नहीं हटाना है। इसी तरह आप सकता है बदलाव के साथ (पहला तत्व निकालने के लिए) return s[1:]जो भी मूल सवाल का जवाब नहीं है।
shadyyx

2
हम्म, वास्तव में नहीं। यह: s[i] = s[len(s)-1]निश्चित रूप से सूचकांक में तत्व को अंतिम तत्व की प्रतिलिपि बनाता है i। फिर, return s[:len(s)-1]अंतिम तत्व के बिना टुकड़ा लौटाता है। वहां दो बयान दिए।
ब्रैड पीबॉडी 19


1
@ मोर्गनोकॉन गोलंग में, सरणियाँ 0-इंडेक्स हैं, जिसका अर्थ है कि लंबाई 2 की एक सरणी के लिए वैध सूचकांक 0 और 1. हैं। वास्तव में, यह फ़ंक्शन सरणी की सीमा की जांच नहीं करता है, और एक वैध सूचकांक प्रदान करने की अपेक्षा करता है। जब लेन (गिरफ्तार) == 2 , मान्य तर्क इस प्रकार 0 या 1 हैं । और कुछ भी सीमा से बाहर पहुंच को ट्रिगर करेगा, और गो घबराएगा।
टी। क्लेवेरी

41

स्लाइस से एक तत्व निकालें (इसे 'रि-स्लाइसिंग' कहा जाता है):

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]
}

8
यह इंगित करते हुए कि यह 'री-स्लाइसिंग' है और यह अपेक्षाकृत महंगा है, हालांकि यह गो में ऐसा करने का मुहावरेदार तरीका है। बस इसे एक ऑपरेशन के साथ भ्रमित न करें जैसे कि एक लिंक्ड सूची से नोड को निकालना क्योंकि यह वह नहीं है और यदि आप इसे बहुत कुछ करने जा रहे हैं, विशेष रूप से बड़े संग्रह के साथ, तो आपको वैकल्पिक डिजाइनों पर विचार करना चाहिए जो इससे बचते हैं।
evanmcdonnal

हां यह गोलंग में मुहावरेदार तरीका है, और यहां तक ​​कि सी / असेंबली में सॉर्ट किए गए सरणी से एक यादृच्छिक तत्व को हटाने के लिए महंगा है, आपको बाईं ओर सभी सही तत्वों को एक स्थान पर शिफ्ट (कॉपी) करने की आवश्यकता है। हां कुछ उपयोग के मामले में लिस्ट से यादृच्छिक तत्व को हटाने के लिए लिंक्ड सूची बेहतर समाधान है।

1
ध्यान दें कि यह विधि सभी को संशोधित करती है और अब n और सभी एक ही अंतर्निहित सरणी के भाग को इंगित करती है। इससे आपके कोड में कीड़े होने की संभावना है।
मांचू जूल

1
यह त्रुटि हो रही है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]:
ओह्हत्थ्वारुन

10
इस का कारण होता panicहै, तो सूचकांक स्लाइस में अंतिम तत्व है
इस्पात

28

मामूली बिंदु (कोड गोल्फ), लेकिन उस मामले में जहां ऑर्डर मायने नहीं रखता है, आपको मूल्यों को स्वैप करने की आवश्यकता नहीं है। बस अंतिम स्थिति के डुप्लिकेट के साथ हटाए जा रहे सरणी स्थिति को अधिलेखित करें और फिर एक काटे गए सरणी को वापस करें।

func remove(s []int, i int) []int {
    s[i] = s[len(s)-1]
    return s[:len(s)-1]
}

एक ही परिणाम।


13
सबसे पठनीय कार्यान्वयन पहले तत्व को निर्दिष्ट सूचकांक में कॉपी करना होगा s[i] = s[0], फिर केवल अंतिम एन -1 तत्वों के साथ एक सरणी लौटाएं। return s[1:]
कैंट

4
खेल का मैदान के समाधान का खेल
stevenspiel

2
@ s[1:]बनाम करने से समस्या s[:len(s)-1]यह है कि यदि बाद में appendएड हो जाता है या डिलीट हो जाता है, तो यह बेहतर प्रदर्शन करेगा append। बाद में स्लाइस क्षमता बनी रहती है, जहां-जहां पूर्व नहीं है।
डेव सी

1
यदि आप इस फ़ंक्शन के साथ 0 वें तत्व को निकालते हैं, तो यह परिणाम को प्रभावित करता है।
ivarec

22

यह देखने में थोड़ा अजीब है लेकिन यहां ज्यादातर जवाब खतरनाक हैं और वास्तव में वे क्या कर रहे हैं, इस पर ग्लॉस। उस मूल प्रश्न को देखते हुए, जिसमें किसी वस्तु को स्लाइस से हटाने के बारे में पूछा गया था कि स्लाइस की एक प्रति बनाई जा रही है और फिर उसे भरा जा रहा है। यह सुनिश्चित करता है कि जैसे ही स्लाइस आपके कार्यक्रम के आसपास से गुजरेगा, आप सूक्ष्म बग का परिचय नहीं देंगे।

इस धागे और मूल पोस्ट में उपयोगकर्ताओं के उत्तरों की तुलना करने वाला कुछ कोड यहां दिया गया है। यहाँ इस कोड के साथ गड़बड़ करने के लिए एक खेल का मैदान है।

अपडेशन बेस्ड रिमूवल

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]
}

उपरोक्त उदाहरण में आप मुझे एक स्लाइस बना सकते हैं और इसे मैन्युअल रूप से संख्या 0 से 9. तक भर सकते हैं। फिर हम सभी से इंडेक्स 5 हटाते हैं और इसे इंडेक्स निकालने के लिए असाइन करते हैं। हालाँकि जब हम सभी का प्रिंट आउट लेते हैं तो हम देखते हैं कि इसे संशोधित किया गया है। ऐसा इसलिए है क्योंकि स्लाइस एक अंतर्निहित सरणी के संकेत हैं। इसे लिखने के removeIndexकारणों allको संशोधित करने के साथ-साथ अंतर allएक तत्व से अधिक लंबा है जो अब उपलब्ध नहीं है removeIndex। आगे हम एक मान बदलते हैं removeIndexऔर हम allसंशोधित रूप में अच्छी तरह से देख सकते हैं । प्रभावी इस पर कुछ और विस्तार में जाता है।

निम्नलिखित उदाहरण मैं नहीं जाऊँगा, लेकिन यह हमारे उद्देश्यों के लिए एक ही काम करता है। और सिर्फ यह दर्शाता है कि कॉपी का उपयोग करना अलग नहीं है।

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]
}

सवाल मूल जवाब

मूल प्रश्न को देखते हुए यह उस स्लाइस को संशोधित नहीं करता है जो किसी आइटम को हटा रही है। इस पृष्ठ में आने वाले अधिकांश लोगों के लिए इस सूत्र में मूल उत्तर को सर्वश्रेष्ठ बनाना।

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]
}

जैसा कि आप देख सकते हैं कि यह आउटपुट कार्य करता है क्योंकि अधिकांश लोग अपेक्षा करते हैं और संभावना है कि अधिकांश लोग क्या चाहते हैं। संशोधन में originalRemoveपरिवर्तन का कारण नहीं है allऔर सूचकांक को हटाने और इसे असाइन करने के संचालन में परिवर्तन नहीं होता है! बहुत खुबस!

यह कोड थोड़ा लंबा है, हालांकि इसके बाद के संस्करण को इसमें बदला जा सकता है।

एक सही जवाब

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]
}

लगभग मूल हटाने सूचकांक समाधान के समान है लेकिन हम लौटने से पहले संलग्न करने के लिए एक नया टुकड़ा बनाते हैं।


3
यह सवाल का जवाब होना चाहिए क्योंकि इसकी एकमात्र व्याख्या जो स्लाइस के बैकिंग एरे को संशोधित करने के जोखिम की व्याख्या करती है
जेसगेंट

एपेंड आधारित निष्कासन में, पहले स्लाइस allको भी बदल दिया जाता है removeIndex := RemoveIndex(all, 5)क्योंकि एपेंड एक ही अंतर्निहित सरणी का पुन: उपयोग करता है यदि इसमें पर्याप्त क्षमता है (निश्चित रूप से एक तत्व को हटाने से अधिक क्षमता की आवश्यकता नहीं है)। इसके विपरीत अगर हम तत्वों को जोड़ते हैं और असाइन करते हैं removeIndex, तो एपेंड एक नई सरणी आवंटित allकरेगा और नहीं बदलेगा।
काला

12

इस तरह आप है हटाएँ एक से टुकड़ा golang रास्ता । आपको एक फ़ंक्शन बनाने की आवश्यकता नहीं है जो इसे ऐपेंड में बनाया गया है। इसे यहाँ आज़माएं 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]

8

पुस्तक द गो प्रोग्रामिंग लैंग्वेज से

एक स्लाइस के बीच से एक तत्व को निकालने के लिए, शेष तत्वों के क्रम को संरक्षित करते हुए, अंतर को भरने के लिए उच्च-क्रम वाले तत्वों को एक-एक करके नीचे स्लाइड करने के लिए प्रतिलिपि का उपयोग करें:

func remove(slice []int, i int) []int {
  copy(slice[i:], slice[i+1:])
  return slice[:len(slice)-1]
}

3
ध्यान दें कि यह विधि मूल टुकड़ा को संशोधित करने का कारण बनता है।
मांचू जूल

7

मैं स्लाइस में आइटम को हटाने के लिए नीचे का दृष्टिकोण लेता हूं। यह दूसरों के लिए पठनीयता में मदद करता है। और अपरिवर्तनीय भी।

func remove(items []string, item string) []string {
    newitems := []string{}

    for _, i := range items {
        if i != item {
            newitems = append(newitems, i)
        }
    }

    return newitems
}

मुझे यह दृष्टिकोण बेहतर लगता है कि आप वास्तव में आइटम की सभी घटनाओं को हटा रहे हैं।
eexit

यह आसानी से टुकड़ा से कई वस्तुओं को छानने के लिए रूपांतरित हो सकता है, अच्छा!
एल्डैड लेवी

1

शायद आप इस विधि को आजमा सकते हैं:

// 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)
    }
}

उपयोग:

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)

परिणाम:

0, 1, 2, 4, 5
"0", "1", "2", "3", "5"

1
शायद इसलिए क्योंकि यह मुहावरेदार और अति-इंजीनियर नहीं है कि सवाल क्या पूछ रहा है। यह इसे हल करने का एक दिलचस्प तरीका है लेकिन किसी को भी इसका उपयोग नहीं करना चाहिए।
मिसेचुएट

1
धन्यवाद! वास्तव में एक इंटरफ़ेस के साथ मेरे लिए बस ठीक काम किया, क्योंकि यह सार्वभौमिक लगता है, शायद
DADi590

1

शायद यह कोड मदद करेगा।

यह दिए गए इंडेक्स के साथ आइटम को हटाता है।

सरणी को हटाता है, और इंडेक्स फ़ंक्शन की तरह एक नया सरणी को हटाने और वापस करने के लिए सूचकांक।

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]
}

यहाँ आप कोड के साथ खेल सकते हैं: https://play.golang.org/p/aX1Qj40uTVs


1

यह करने के लिए सबसे अच्छा तरीका है app समारोह का उपयोग करें:

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


1

बिना स्थानांतरित किए यहां एक रास्ता खोजें ।

  • क्रम बदलता है
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]

0

जब तक आप सामग्री की देखभाल नहीं करते तब तक आपको हर एक तत्व की जाँच करने की आवश्यकता नहीं है और आप स्लाइस एपेंड का उपयोग कर सकते हैं। कोशिश करके देखो

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")
}

-1

यहाँ संकेत के साथ खेल का मैदान उदाहरण है। 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)
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.