गो में दो स्लाइस को मिलाएं


477

मैं स्लाइस [1, 2]और स्लाइस को संयोजित करने का प्रयास कर रहा हूं [3, 4]। मैं गो में यह कैसे कर सकता हूं?

मैंने कोशिश की:

append([]int{1,2}, []int{3,4})

लेकिन मिल गया:

cannot use []int literal (type []int) as type int in append

हालाँकि, दस्तावेज़ीकरण से यह संकेत मिलता है कि यह संभव है, मुझे क्या याद आ रहा है?

slice = append(slice, anotherSlice...)

जवाबों:


877

दूसरे स्लाइस के बाद डॉट्स जोड़ें:

//---------------------------vvv
append([]int{1,2}, []int{3,4}...)

यह किसी अन्य वैरडीकल फंक्शन की तरह है।

func foo(is ...int) {
    for i := 0; i < len(is); i++ {
        fmt.Println(is[i])
    }
}

func main() {
    foo([]int{9,8,7,6,5}...)
}

37
append()एक चर समारोह, और ...आप एक स्लाइस से एक चर समारोह के लिए कई तर्क पारित करने देता है।

11
जब स्लाइस काफी बड़ा होता है तो क्या यह बिल्कुल अच्छा होता है? या कंपाइलर वास्तव में सभी तत्वों को मापदंडों के रूप में पारित नहीं करता है?
ताड़

15
@ लोड: यह वास्तव में उन्हें बाहर नहीं फैलता है। foo()ऊपर के उदाहरण में, isपैरामीटर मूल स्लाइस की एक प्रति रखता है, जो यह कहता है कि इसमें एक ही अंतर्निहित सरणी, लेन और कैप के हल्के-वजन संदर्भ की एक प्रति है। यदि fooफ़ंक्शन किसी सदस्य को बदल देता है, तो मूल पर परिवर्तन दिखाई देगा। यहाँ एक डेमो है । तो केवल असली ओवरहेड यह होगा कि यह एक नया स्लाइस बनाता है यदि आपके पास पहले से एक नहीं था, जैसे: foo(1, 2, 3, 4, 5)जो एक नया स्लाइस बनाएगा जो isधारण करेगा।

2
आह। यदि मैं सही ढंग से समझता हूं, तो वैरिएडिक फ़ंक्शन वास्तव में पैरामीटर की एक सरणी (स्टैक पर प्रत्येक पैरामीटर के बजाय) की तरह लागू किया जाता है? और जब से आप स्लाइस में पास होते हैं, यह वास्तव में एक पर एक मैप करता है?
ताड़

@ लोड: हाँ, जब आप ...किसी मौजूदा स्लाइस का उपयोग करते हैं, तो यह बस उस स्लाइस को पास करता है। जब आप व्यक्तिगत तर्क पास करते हैं, तो यह उन्हें एक नए स्लाइस में इकट्ठा करता है और इसे पास करता है। मुझे सटीक यांत्रिकी का प्रथम-ज्ञान नहीं है, लेकिन मुझे लगता है कि यह: foo(1, 2, 3, 4, 5)और यह: इस के लिए func foo(is ...int) {सिर्फ डी-शर्करा: foo([]int{1, 2, 3, 4, 5})और यह func foo(is []int) {:।

77

स्लाइस के लिए आवेदन करना और उसकी प्रतिलिपि बनाना

वेरिएडिक फ़ंक्शन appendशून्य या अधिक प्रकार के मानों xको जोड़ता है , जो एक स्लाइस प्रकार होना चाहिए, और परिणामस्वरूप स्लाइस, प्रकार का भी लौटाता है । मानों को उस प्रकार के पैरामीटर में पास किया जाता है जहां तत्व प्रकार है और संबंधित पैरामीटर पासिंग नियम लागू होते हैं। एक विशेष मामले के रूप में, परिशिष्ट भी पहले तर्क प्रकार के एक दूसरे तर्क के साथ टाइप करने के लिए स्वीकार्य स्वीकार करता है । यह प्रपत्र स्ट्रिंग के बाइट्स को जोड़ता है।sSSx...TTS[]bytestring...

append(s S, x ...T) S  // T is the element type of S

s0 := []int{0, 0}
s1 := append(s0, 2)        // append a single element     s1 == []int{0, 0, 2}
s2 := append(s1, 3, 5, 7)  // append multiple elements    s2 == []int{0, 0, 2, 3, 5, 7}
s3 := append(s2, s0...)    // append a slice              s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}

तर्कों को पारित करना ... मापदंडों

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

आपके प्रश्न का उत्तर गो प्रोग्रामिंग भाषा विशिष्टताs3 := append(s2, s0...) में उदाहरण है । उदाहरण के लिए,

s := append([]int{1, 2}, []int{3, 4}...)

6
नोट: एपेंड का सामान्य उपयोग (slice1, slice2 ...) मुझे काफी खतरनाक लगता है। यदि स्लाइस 1 एक बड़े ऐरे का स्लाइस है, तो उस ऐरे के मान स्लाइस 2 द्वारा अधिलेखित हो जाएंगे। (यह मुझे परेशान करता है कि यह एक सामान्य चिंता का विषय नहीं है?)
ह्यूगो

7
@ ह्यूगो यदि आप अपने ऐरे के एक स्लाइस पर "हाथ" लगाते हैं, तो जान लें कि स्लाइस "ओनर" उस ऐरे के कुछ हिस्सों को देख / ओवरराइट कर पाएगा जो स्लाइस की वर्तमान लंबाई से परे हैं। यदि आप यह नहीं चाहते हैं, तो आप एक पूर्ण स्लाइस अभिव्यक्ति (के रूप में a[low : high : max]) का उपयोग कर सकते हैं जो अधिकतम क्षमता भी निर्दिष्ट करता है । उदाहरण के लिए स्लाइस a[0:2:4]की एक क्षमता होगी 4और इसे उससे आगे के तत्वों को शामिल करने के लिए नहीं हटाया जा सकता है, भले ही बैकिंग सरणी में एक हजार तत्व हो।
आईसीएजे

30

अन्य उत्तरों के खिलाफ कुछ भी नहीं है, लेकिन मुझे उन उदाहरणों की तुलना में डॉक्स में संक्षिप्त विवरण अधिक आसानी से समझ में आता है:

func append

func append(slice []Type, elems ...Type) []Typeएपेंडेड बिल्ट-इन फ़ंक्शन तत्वों को एक स्लाइस के अंत में जोड़ता है। यदि इसकी पर्याप्त क्षमता है, तो नए तत्वों को समायोजित करने के लिए गंतव्य को हटा दिया जाता है। यदि ऐसा नहीं होता है, तो एक नया अंतर्निहित सरणी आवंटित किया जाएगा। अद्यतन स्लाइस को परिशिष्ट लौटाता है। इसलिए एपेंड के परिणाम को स्टोर करना आवश्यक है, अक्सर स्लाइस को पकड़े हुए चर में ही:

slice = append(slice, elem1, elem2)
slice = append(slice, anotherSlice...)

एक विशेष मामले के रूप में, एक स्ट्रिंग को बाइट स्लाइस में जोड़ना कानूनी है, जैसे:

slice = append([]byte("hello "), "world"...)

1
धन्यवाद! मेरे लिए मूल्यवान!
कोरजाविन इवान

23

मुझे लगता है कि यह इंगित करना और जानना महत्वपूर्ण है कि यदि गंतव्य स्लाइस (आप जिस स्लाइस में संलग्न हैं) में पर्याप्त क्षमता है, तो अपेंडिस "इन-प्लेस" होगा, डेस्टीनेशन को (reslicing) बढ़ाने के बढ़ाने का इसकी लंबाई करने के लिए) उपयुक्त तत्वों को समायोजित करने में सक्षम)।

इसका मतलब यह है कि यदि गंतव्य एक बड़े सरणी या स्लाइस को बनाकर बनाया गया था जिसके परिणामस्वरूप टुकड़ा की लंबाई से परे अतिरिक्त तत्व हैं, तो वे अधिलेखित हो सकते हैं।

प्रदर्शित करने के लिए, इस उदाहरण को देखें:

a := [10]int{1, 2}
fmt.Printf("a: %v\n", a)

x, y := a[:2], []int{3, 4}
fmt.Printf("x: %v, y: %v\n", x, y)
fmt.Printf("cap(x): %v\n", cap(x))

x = append(x, y...)
fmt.Printf("x: %v\n", x)

fmt.Printf("a: %v\n", a)

आउटपुट (इसे खेल के मैदान पर आज़माएं ):

a: [1 2 0 0 0 0 0 0 0 0]
x: [1 2], y: [3 4]
cap(x): 10
x: [1 2 3 4]
a: [1 2 3 4 0 0 0 0 0 0]

हमने aलंबाई के साथ एक "बैकिंग" सरणी बनाई 10। फिर हम xइस aएरे को स्लाइस करके डेस्टिनेशन स्लाइस बनाते हैं , yकंपोजिट शाब्दिक का उपयोग करके स्लाइस बनाया जाता है []int{3, 4}। अब जब हम yकरने के लिए अपील करते हैं x, तो परिणाम अपेक्षित है [1 2 3 4], लेकिन क्या आश्चर्य की बात हो सकती है कि बैकिंग सरणी aभी बदल गई है, क्योंकि क्षमता xहै 10जो yइसे जोड़ने के लिए पर्याप्त है , इसलिए xइसे हटा दिया गया है जो उसी aबैकिंग सरणी का उपयोग करेगा , औरappend() के तत्वों की नकल करेंगेy वहाँ के ।

यदि आप इससे बचना चाहते हैं, तो आप एक पूर्ण स्लाइस अभिव्यक्ति का उपयोग कर सकते हैं जिसका स्वरूप है

a[low : high : max]

जो एक स्लाइस का निर्माण करता है और इसके द्वारा निर्धारित स्लाइस की क्षमता को भी नियंत्रित करता है max - low

संशोधित उदाहरण देखें (केवल अंतर यह है कि हम xइस तरह बनाते हैं x = a[:2:2]:

a := [10]int{1, 2}
fmt.Printf("a: %v\n", a)

x, y := a[:2:2], []int{3, 4}
fmt.Printf("x: %v, y: %v\n", x, y)
fmt.Printf("cap(x): %v\n", cap(x))

x = append(x, y...)
fmt.Printf("x: %v\n", x)

fmt.Printf("a: %v\n", a)

आउटपुट (इसे खेल के मैदान पर आज़माएं )

a: [1 2 0 0 0 0 0 0 0 0]
x: [1 2], y: [3 4]
cap(x): 2
x: [1 2 3 4]
a: [1 2 0 0 0 0 0 0 0 0]

जैसा कि आप देख सकते हैं, हम एक ही xपरिणाम प्राप्त करते हैं, लेकिन बैकिंग सरणी aनहीं बदली, क्योंकि क्षमता xकेवल "थी" 2(पूर्ण टुकड़ा अभिव्यक्ति के लिए धन्यवाद a[:2:2])। तो एपेंड करने के लिए, एक नया बैकिंग एरे आवंटित किया जाता है जो दोनों के तत्वों को संग्रहीत कर सकता है xऔर y, जो अलग है a


2
यह मेरे सामने आने वाली समस्या के लिए बहुत मददगार है। धन्यवाद।
यानि

9

मैं @icza उत्तर पर जोर देना चाहूंगा और इसे थोड़ा सरल कर दूंगा क्योंकि यह एक महत्वपूर्ण अवधारणा है। मुझे लगता है कि पाठक स्लाइस से परिचित है ।

c := append(a, b...)

यह प्रश्न का एक मान्य उत्तर है। लेकिन अगर आपको अलग-अलग संदर्भों में कोड में बाद में स्लाइस 'ए' और 'सी' का उपयोग करने की आवश्यकता है, तो यह स्लाइस को सुरक्षित करने का सुरक्षित तरीका नहीं है।

समझाने के लिए, अभिव्यक्ति को स्लाइस के संदर्भ में नहीं, बल्कि अंतर्निहित सरणियों के संदर्भ में पढ़ने दें:

"ए 'की (अंतर्निहित) एरे को ले लीजिए और एरे से तत्वों को' बी 'में जोड़ दें। यदि ए' ए 'में' बी 'से सभी तत्वों को शामिल करने की पर्याप्त क्षमता है - तो' सी 'का अंतर्निहित एरे नया सरणी नहीं होगा। यह वास्तव में एरे 'ए' होगा। मूल रूप से, स्लाइस 'ए' (ए) अंतर्निहित एरे 'ए' के ​​तत्वों को दिखाएगा, और स्लाइस 'सी' एरे 'ए' के ​​लेन (सी) को दिखाएगा। "

append () आवश्यक रूप से एक नया सरणी नहीं बनाता है! इससे अप्रत्याशित परिणाम हो सकते हैं। देखें खेल का मैदान उदाहरण देखें

यदि आप यह सुनिश्चित करना चाहते हैं कि स्लाइस के लिए नई सरणी आवंटित की जाए तो हमेशा मेक () फ़ंक्शन का उपयोग करें। उदाहरण के लिए यहाँ कुछ बदसूरत लेकिन कार्य के लिए पर्याप्त विकल्प हैं।

la := len(a)
c := make([]int, la, la + len(b))
_ = copy(c, a)
c = append(c, b...)

la := len(a)
c := make([]int, la + len(b))
_ = copy(c, a)
_ = copy(c[la:], b)

इन दुष्प्रभावों की ओर इशारा करने के लिए धन्यवाद। आश्चर्यजनक रूप से इस संशोधित सेंजेरियो के विपरीत है। play.golang.org/p/9FKo5idLBj4 यद्यपि अतिरिक्त क्षमता प्रदान करते समय, व्यक्ति को सावधानीपूर्वक प्रशंसनीय अंतर्ज्ञान के खिलाफ इन गूढ़ पक्षधरता के बारे में सोचना चाहिए।
olippuner

5

append () फ़ंक्शन और प्रसार ऑपरेटर

appendमानक स्लैंग लाइब्रेरी में दो स्लाइस को विधि का उपयोग करके समेटा जा सकता है । जो variadicफंक्शन ऑपरेशन के समान है । इसलिए हमें उपयोग करने की आवश्यकता है...

package main

import (
    "fmt"
)

func main() {
    x := []int{1, 2, 3}
    y := []int{4, 5, 6}
    z := append([]int{}, append(x, y...)...)
    fmt.Println(z)
}

उपरोक्त कोड का आउटपुट है: [१ २ ३ ४ ५ ६]


2

append([]int{1,2}, []int{3,4}...)काम करेगा। पास करने के लिए तर्क...मापदंडों के करना।

यदि प्रकार के fअंतिम पैरामीटर pके साथ परिवर्तनशील है ...T, तो fप्रकार के भीतर प्रकार के pबराबर है[]T

यदि fकोई वास्तविक तर्क नहीं pदिया जाता pहै , तो यह मान लिया जाता हैnil

अन्यथा, पारित मूल्य []Tएक नए अंतर्निहित सरणी के साथ एक नया टुकड़ा है जिसका क्रमिक तत्व वास्तविक तर्क हैं, जिन्हें सभी के लिए असाइन किया जाना चाहिए T। इसलिए स्लाइस की लंबाई और क्षमता के लिए बाध्य तर्कों की संख्या हैp और प्रत्येक कॉल साइट के लिए अलग-अलग हो सकते हैं।

फ़ंक्शन और कॉल को देखते हुए

func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.