एक स्लाइस के लिए विधि शामिल है


जवाबों:


226

मुस्तफा ने पहले ही बताया है कि इस तरह की विधि लिखने के लिए तुच्छ है, और mkb ने आपको सॉर्ट पैकेज से द्विआधारी खोज का उपयोग करने का संकेत दिया। लेकिन अगर आप बहुत सारे ऐसे चेक करने जा रहे हैं, तो आप इसके बजाय एक मैप का उपयोग करने पर भी विचार कर सकते हैं।

यह जांचना तुच्छ है कि क्या एक विशेष मानचित्र कुंजी value, ok := yourmap[key]मुहावरे का उपयोग करके मौजूद है । चूंकि आप मूल्य में दिलचस्पी नहीं रखते हैं, आप map[string]struct{}उदाहरण के लिए भी बना सकते हैं । struct{}यहां खाली का उपयोग करने से यह फायदा होता है कि इसके लिए किसी अतिरिक्त स्थान की आवश्यकता नहीं होती है और गो का आंतरिक मानचित्र प्रकार उस प्रकार के मूल्यों के लिए अनुकूलित होता है। इसलिए, map[string] struct{}गो दुनिया में सेट के लिए एक लोकप्रिय विकल्प है।


27
यह भी ध्यान दें, कि आपको struct{}{}खाली संरचना का मूल्य प्राप्त करने के लिए लिखना है ताकि आप इसे अपने मानचित्र में पास कर सकें जब आप एक तत्व जोड़ना चाहते हैं। बस इसे आज़माएं, और यदि आपको कोई समस्या आती है, तो बेझिझक पूछें। यदि आप को समझना आसान है (जब तक आपके पास भारी मात्रा में डेटा नहीं है) तो आप मुस्तफा के समाधान का भी उपयोग कर सकते हैं।
tux21b

5
समाधान सरल है, यह सच है। लेकिन रनटाइम में इस तरह की बुनियादी कार्यक्षमता को जोड़ने में क्या लगता है? मुझे गितुब पर गो रेपो में ऐसे मुद्दे नहीं मिले। यह दुखद और अजीब है।
इगोर पेत्रोव

1
कैसे करता है map[string] boolके साथ तुलना करें map[string] struct{}map[string] struct{}एक हैक की तरह लगता है विशेष रूप से एक खाली संरचना को शुरूstruct {}{}
vadasambar

@IgorPetrov ने सहमति व्यक्त की, मुझे आश्चर्य है कि इस तरह की बुनियादी सुविधा पहले से ही रनटाइम में नहीं है।
जेकलूम

180

नहीं, ऐसी विधि मौजूद नहीं है, लेकिन लिखने के लिए तुच्छ है:

func contains(s []int, e int) bool {
    for _, a := range s {
        if a == e {
            return true
        }
    }
    return false
}

आप नक्शे का उपयोग कर सकते हैं यदि वह लुकअप आपके कोड का एक महत्वपूर्ण हिस्सा है, लेकिन नक्शे में लागत भी है।


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

15
@ एलॉफ़interface{}
एलेक्स लॉकवुड

2
@ एलेक्स लॉकवुड वास्तव में इंटरफेस के साथ काम करेगा?
ओरी बैंड

101
trivial == कोड की 7 पंक्तियाँ जिसमें 1 लूप 1 शाखा शामिल है यदि कथन और 1 तुलना हो? मुझे लगता है कि मैं यहाँ कुछ याद कर रहा हूँ ...
कुलश्रेष्ठ

3
लेकिन इन्हें गो कोर में ही क्यों न जोड़ा जाए?
लूना लवगूड

16

यदि स्लाइस को सॉर्ट किया जाता है, तो sortपैकेज में कार्यान्वित एक द्विआधारी खोज होती है ।


11

एक का उपयोग करने के बजाय slice, mapएक बेहतर समाधान हो सकता है।

सरल उदाहरण:

package main

import "fmt"


func contains(slice []string, item string) bool {
    set := make(map[string]struct{}, len(slice))
    for _, s := range slice {
        set[s] = struct{}{}
    }

    _, ok := set[item] 
    return ok
}

func main() {

    s := []string{"a", "b"}
    s1 := "a"
    fmt.Println(contains(s, s1))

}

http://play.golang.org/p/CEG6cu4JTf


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

9

प्रकार पैकेज का निर्माण ब्लॉकों प्रदान करता है अगर आपके टुकड़ा क्रमबद्ध है या आप इसे सुलझाने के लिए तैयार हैं।

input := []string{"bird", "apple", "ocean", "fork", "anchor"}
sort.Strings(input)

fmt.Println(contains(input, "apple")) // true
fmt.Println(contains(input, "grow"))  // false

...

func contains(s []string, searchterm string) bool {
    i := sort.SearchStrings(s, searchterm)
    return i < len(s) && s[i] == searchterm
}

SearchStringवापस करने का वादा करता है the index to insert x if x is not present (it could be len(a)), इसलिए उस की एक जांच से पता चलता है कि क्या स्ट्रिंग को छांटा गया है।


समय के संदर्भ में, नियमित खोज है O(n)और यह समाधान इसे बनाता है O(n*log(n))
plesiv

@plesiv यह एक द्विआधारी खोज है, AFAICS। ऐसा नहीं होगा कि यह हे (लॉग एन)?
हेनरिक एओड सोरेंसन

हां, बाइनरी-खोज और फ़ंक्शन containsहैं O(log(n)), लेकिन समग्र दृष्टिकोण O(n*log(n))सॉर्ट के कारण है।
plesiv

3

आप ऐसे इंटरफ़ेस पर पुनरावृति करने के लिए प्रतिबिंबित पैकेज का उपयोग कर सकते हैं जिसका ठोस प्रकार एक टुकड़ा है:

func HasElem(s interface{}, elem interface{}) bool {
    arrV := reflect.ValueOf(s)

    if arrV.Kind() == reflect.Slice {
        for i := 0; i < arrV.Len(); i++ {

            // XXX - panics if slice element points to an unexported struct field
            // see https://golang.org/pkg/reflect/#Value.Interface
            if arrV.Index(i).Interface() == elem {
                return true
            }
        }
    }

    return false
}

https://play.golang.org/p/jL5UD7yCNq


3
सुनिश्चित करें कि आप प्रतिबिंबित पैकेज का उपयोग कर सकते हैं लेकिन सिर्फ इसलिए कि आप कर सकते हैं, इसका मतलब यह नहीं है कि आपको चाहिए। प्रतिबिंब बहुत महंगा है।
जस्टिन ओम्स

3

यदि किसी कुंजी के आधार पर वस्तुओं को खोजने के लिए मानचित्र का उपयोग करना संभव नहीं है, तो आप गॉडेरिव टूल पर विचार कर सकते हैं । Goderive में एक विधि का विशिष्ट प्रकार का कार्यान्वयन उत्पन्न होता है, जो आपके कोड को पठनीय और कुशल बनाता है।

उदाहरण;

type Foo struct {
    Field1 string
    Field2 int
} 

func Test(m Foo) bool {
     var allItems []Foo
     return deriveContainsFoo(allItems, m)
}

DeriveContainsFoo विधि उत्पन्न करने के लिए:

  • के साथ Goderive स्थापित करें go get -u github.com/awalterschulze/goderive
  • goderive ./...अपने कार्यक्षेत्र फ़ोल्डर में चलाएँ

यह विधि deriveContains के लिए बनाई जाएगी:

func deriveContainsFoo(list []Foo, item Foo) bool {
    for _, v := range list {
        if v == item {
            return true
        }
    }
    return false
}

गोदरिव में एक कार्यात्मक प्रोग्रामिंग शैली को लागू करने के लिए कुछ अन्य उपयोगी सहायक विधियों के लिए समर्थन है।


2
func Contain(target interface{}, list interface{}) (bool, int) {
    if reflect.TypeOf(list).Kind() == reflect.Slice || reflect.TypeOf(list).Kind() == reflect.Array {
        listvalue := reflect.ValueOf(list)
        for i := 0; i < listvalue.Len(); i++ {
            if target == listvalue.Index(i).Interface() {
                return true, i
            }
        }
    }
    if reflect.TypeOf(target).Kind() == reflect.String && reflect.TypeOf(list).Kind() == reflect.String {
        return strings.Contains(list.(string), target.(string)), strings.Index(list.(string), target.(string))
    }
    return false, -1
}

2

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

type Identifiable interface{
    GetIdentity() string
}

func IsIdentical(this Identifiable, that Identifiable) bool{
    return (&this == &that) || (this.GetIdentity() == that.GetIdentity())
}

func contains(s []Identifiable, e Identifiable) bool {
    for _, a := range s {
        if IsIdentical(a,e) {
            return true
        }
    }
    return false
}

1
"इससे अधिक नहीं कि आपको अन्य भाषाओं में क्या करना होगा" वास्तव में सही नहीं है - जैसे C # Contains()में लागू किया गया है List<T>, इसलिए आपको केवल Equals()उस काम के लिए ही लागू करना होगा।
जॉर्ज

1

मैंने इन उत्तरों से समाधान के साथ एक बहुत ही सरल बेंचमार्क बनाया।

https://gist.github.com/NorbertFenk/7bed6760198800207e84f141c41d93c7

यह वास्तविक बेंचमार्क नहीं है क्योंकि शुरू में, मैंने बहुत सारे तत्व नहीं डाले हैं, लेकिन कांटे और इसे बदलने के लिए स्वतंत्र महसूस करते हैं।


मैंने इसके बारे में सोचा, लेकिन यह इस तथ्य के कारण नहीं है कि मेरी मशीन इतनी शक्तिशाली नहीं है।
एफ। नॉर्बर्ट

0

इसे थोड़ा 'हैकी' माना जा सकता है, लेकिन स्लाइस के आकार और सामग्री के आधार पर, आप स्लाइस को एक साथ जोड़ सकते हैं और एक स्ट्रिंग खोज कर सकते हैं।

उदाहरण के लिए आपके पास एक स्लाइस है जिसमें एकल शब्द मान हैं (जैसे "हाँ", "नहीं", "हो सकता है")। इन परिणामों को एक स्लाइस से जोड़ा जाता है। यदि आप जांचना चाहते हैं कि क्या इस स्लाइस में कोई "शायद" परिणाम है, तो आप उपयोग कर सकते हैं

exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
  fmt.Println("We have a maybe!")
}

यह कितना उपयुक्त है यह वास्तव में इसके सदस्यों के स्लाइस और लंबाई के आकार पर निर्भर करता है। बड़े स्लाइस या लंबे मूल्यों के लिए प्रदर्शन या उपयुक्तता के मुद्दे हो सकते हैं, लेकिन परिमित आकार के छोटे स्लाइस और सरल मूल्यों के लिए यह वांछित परिणाम प्राप्त करने के लिए एक वैध एक लाइनर है।


उन परिस्थितियों के लिए काम नहीं करेगा जहां तत्वों के समान पाठ हैं लेकिन बिल्कुल समान नहीं हैंexSlice := ["yes and no", "maybe", "maybe another"]
रईस इकबाल

यह एक त्वरित और गंदे एक-लाइनर समाधान को प्राप्त करने के लिए एक अच्छा तरीका है। आपको बस एक अस्पष्ट सीम की आवश्यकता होती है (एक अल्पविराम हो सकता है) और दोनों तारों को ब्रैकेट करने के लिए अतिरिक्त कार्य करें: ","+strings.Join(exSlice,",")+","और",maybe,"
nobar

-1

गो स्टाइल:

func Contains(n int, match func(i int) bool) bool {
    for i := 0; i < n; i++ {
        if match(i) {
            return true
        }
    }
    return false
}


s := []string{"a", "b", "c", "o"}
// test if s contains "o"
ok := Contains(len(s), func(i int) bool {
    return s[i] == "o"
})

2
यह प्रश्न का उत्तर नहीं देता है, न ही अतिरिक्त जानकारी देता है।
क्रोलमैन 12
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.