नक्शे से चाबियों का टुकड़ा मिलना


230

क्या गो में किसी नक्शे से चाबियों का टुकड़ा मिलने का कोई सरल / अच्छा तरीका है?

वर्तमान में मैं मानचित्र पर पुनरावृत्ति कर रहा हूं और एक स्लाइस की कुंजी कॉपी कर रहा हूं:

i := 0
keys := make([]int, len(mymap))
for k := range mymap {
    keys[i] = k
    i++
}

19
सही उत्तर नहीं है, कोई सरल / अच्छा तरीका नहीं है।
dldnh

जवाबों:


202

उदाहरण के लिए,

package main

func main() {
    mymap := make(map[int]string)
    keys := make([]int, 0, len(mymap))
    for k := range mymap {
        keys = append(keys, k)
    }
}

गो में कुशल होने के लिए, मेमोरी आवंटन को कम करना महत्वपूर्ण है।


29
क्षमता के बजाय वास्तविक आकार निर्धारित करना और पूरी तरह से परिशिष्ट से बचना थोड़ा बेहतर है। विवरण के लिए मेरा उत्तर देखें।
विनय पई

3
ध्यान दें कि अगर mymapएक स्थानीय चर नहीं है (और इसलिए बढ़ती / सिकुड़ती है), यह एकमात्र उचित समाधान है - यह सुनिश्चित करता है कि यदि और लूप mymapके प्रारंभ के बीच परिवर्तनों का आकार है , तो कोई आउट नहीं होगा- मुद्दों की सीमा। keysfor
मेल्लवर

12
समवर्ती पहुंच के तहत नक्शे सुरक्षित नहीं हैं, न ही समाधान स्वीकार्य है अगर कोई अन्य गोरोइन मानचित्र बदल सकता है।
विनय पई

@VinayPai यह ठीक है कि कई गोरआउट्स के नक्शे से पढ़ा जाए, लेकिन नहीं लिखा
darethas

@ डेड्रेट्स जो एक आम गलत धारणा है। रेस डिटेक्टर 1.6 के बाद से इस उपयोग को चिह्नित करेगा। जारी नोटों से: "हमेशा की तरह, यदि एक गोरोइन मानचित्र में लिख रहा है, तो किसी अन्य गोरोइन को मानचित्र को पढ़ने या लिखने के लिए समवर्ती रूप से नहीं लिखा जाना चाहिए। यदि रनटाइम इस स्थिति का पता लगाता है, तो यह निदान को प्रिंट करता है और प्रोग्राम को क्रैश करता है।" golang.org/doc/go1.6#runtime
विनय पै

375

यह एक पुराना सवाल है, लेकिन यहाँ मेरे दो सेंट हैं। पीटरो का जवाब थोड़ा अधिक संक्षिप्त है, लेकिन थोड़ा कम कुशल है। आप पहले से ही जानते हैं कि यह कितना बड़ा होने जा रहा है इसलिए आपको एपेंड का उपयोग करने की आवश्यकता नहीं है:

keys := make([]int, len(mymap))

i := 0
for k := range mymap {
    keys[i] = k
    i++
}

ज्यादातर स्थितियों में शायद इससे बहुत फर्क नहीं पड़ेगा, लेकिन यह बहुत अधिक काम नहीं है, और मेरे परीक्षणों में (1,000,000 यादृच्छिक int64कुंजी के साथ मानचित्र का उपयोग करना और फिर प्रत्येक विधि के साथ दस बार कुंजियों का सरणी उत्पन्न करना), यह लगभग था एपेंड का उपयोग करने की तुलना में सीधे सरणी के सदस्यों को आवंटित करने के लिए 20% तेज।

यद्यपि क्षमता स्थापित करने से वास्तविकताओं का सफाया हो जाता है, फिर भी प्रत्येक परिशिष्ट पर क्षमता तक पहुँचने के लिए अपेंड को अतिरिक्त कार्य करना पड़ता है।


46
यह ओपी कोड के समान ही दिखता है। मैं मानता हूं कि यह बेहतर तरीका है, लेकिन अगर मैं इस उत्तर के कोड और ओपी के कोड के बीच के अंतर को याद कर रहा हूं तो मैं उत्सुक हूं।
एम्मेली विल्सन

4
अच्छी बात है, मैंने किसी तरह अन्य उत्तरों को देखा और याद किया कि मेरा उत्तर ओपी के समान है। अरे ठीक है, कम से कम अब हम लगभग जानते हैं कि अनावश्यक रूप से अपेंडेंस का उपयोग करने के लिए जुर्माना क्या है :)
विनय पाइ

5
तुम क्यों, सीमा के साथ एक सूचकांक उपयोग नहीं कर रहे for i, k := range mymap{। इस तरह से आपको i ++ की आवश्यकता नहीं है?
मवंडई

30
शायद मैं यहां कुछ याद कर रहा हूं, लेकिन अगर आपने किया i, k := range mymap, तो iचाबियाँ kहोंगी और नक्शे में उन कुंजियों के अनुरूप मूल्य होंगे। यह वास्तव में आपको चाबियों के एक टुकड़े को आबाद करने में मदद नहीं करेगा।
विनय पई

4
@ अलास्का यदि आप एक अस्थायी काउंटर चर को आवंटित करने की लागत से चिंतित हैं, लेकिन एक फ़ंक्शन कॉल कम स्मृति लेने जा रहा है, तो आपको अपने आप को शिक्षित करना चाहिए कि वास्तव में क्या होता है जब एक फ़ंक्शन कहा जाता है। संकेत: यह एक जादुई भटकाव नहीं है जो मुफ्त में चीजें करता है। यदि आपको लगता है कि वर्तमान में स्वीकृत उत्तर समवर्ती पहुंच के तहत सुरक्षित है, तो आपको मूल बातें भी वापस लेने की आवश्यकता है: blog.golang.org/go-maps-in-action#TOC_6
विनय पई

79

तुम भी प्रकार के साथ चाबियों का एक सरणी ले जा सकते हैं []Valueविधि द्वारा MapKeysstruct के Valueपैकेज से "को प्रतिबिंबित":

package main

import (
    "fmt"
    "reflect"
)

func main() {
    abc := map[string]int{
        "a": 1,
        "b": 2,
        "c": 3,
    }

    keys := reflect.ValueOf(abc).MapKeys()

    fmt.Println(keys) // [a b c]
}

1
मुझे लगता है कि यह एक अच्छा दृष्टिकोण है यदि समवर्ती मानचित्र पहुंच का मौका है: यदि लूप के दौरान नक्शा बढ़ता है तो यह घबराएगा नहीं। प्रदर्शन के बारे में, मुझे वास्तव में यकीन नहीं है, लेकिन मुझे संदेह है कि यह एपेंड के समाधान को बेहतर बनाता है।
एटिला रोमेरो

@AtilaRomero यकीन नहीं है कि इस समाधान के कोई फायदे हैं, लेकिन जब किसी भी उद्देश्य के लिए प्रतिबिंब का उपयोग करें तो यह अधिक उपयोगी है, क्योंकि यह सीधे टाइप किए गए मान के रूप में एक कुंजी लेने की अनुमति देता है।
डेनिस क्रेशिकिन

10
क्या इसे बदलने का कोई तरीका है []string?
डोरोन बेहार

14

इसका उपयोग करने का एक अच्छा तरीका यह होगा append:

keys = []int{}
for k := range mymap {
    keys = append(keys, k)
}

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


10
यह मूल की तुलना में कम कुशल है - एपेंडेड अंतर्निहित सरणी को विकसित करने के लिए कई आवंटन करेगा, और हर कॉल पर स्लाइस की लंबाई को अपडेट करना होगा। कहने keys = make([]int, 0, len(mymap))से आवंटन से छुटकारा मिल जाएगा लेकिन मुझे उम्मीद है कि यह अभी भी धीमा रहेगा।
निक क्रेग-वुड

1
यह उत्तर लेन (मायमैप) का उपयोग करने की तुलना में अधिक सुरक्षित है, अगर कोई अन्य मानचित्र बदलता है जबकि प्रतिलिपि बनाई जा रही है।
एटिला रोमेरो

7

मैंने अन्य प्रतिक्रियाओं में वर्णित तीन तरीकों पर एक स्केचिंग बेंचमार्क बनाया।

स्पष्ट रूप से चाबियों को खींचने से पहले टुकड़ा पूर्व-आवंटित करना appendआईएनजी की तुलना में तेज है , लेकिन आश्चर्यजनक रूप से, reflect.ValueOf(m).MapKeys()विधि बाद की तुलना में काफी धीमी है:

 go run scratch.go
populating
filling 100000000 slots
done in 56.630774791s
running prealloc
took: 9.989049786s
running append
took: 18.948676741s
running reflect
took: 25.50070649s

यहाँ कोड है: https://play.golang.org/p/Z8O6a2jyfTH (खेल के मैदानों में इसे चलाने का दावा करते हुए कि यह बहुत लंबा है, इसलिए, ठीक है, इसे स्थानीय रूप से चलाएं।)


2
अपने keysAppendफ़ंक्शन में, आप keysऐरे की क्षमता निर्धारित कर सकते हैं make([]uint64, 0, len(m)), जिसने मेरे लिए उस फ़ंक्शन के प्रदर्शन को काफी बदल दिया है।
15 जुलाई को कीथभंटर

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