कुंजी द्वारा क्रमबद्ध गो मैप मान


94

जब विषय फ़ंक्शन द्वारा लौटाए गए कोड में दिए गए नक्शे के माध्यम से पुनरावृति होती है, तो चाबियाँ क्रम में दिखाई नहीं दे रही हैं।

मुझे नक्शे में क्रमबद्ध / क्रमबद्ध होने के लिए चाबियाँ कैसे मिल सकती हैं ताकि चाबियाँ क्रम में हों और मूल्य अनुरूप हों?

यहाँ कोड है


जवाबों:


157

जाओ ब्लॉग: जाओ कार्रवाई में नक्शे एक उत्कृष्ट व्याख्या है।

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

यहाँ उदाहरण कोड का मेरा संशोधित संस्करण है: http://play.golang.org/p/dvqcGPYy3-

package main

import (
    "fmt"
    "sort"
)

func main() {
    // To create a map as input
    m := make(map[int]string)
    m[1] = "a"
    m[2] = "c"
    m[0] = "b"

    // To store the keys in slice in sorted order
    keys := make([]int, len(m))
    i := 0
    for k := range m {
        keys[i] = k
        i++
    }
    sort.Ints(keys)

    // To perform the opertion you want
    for _, k := range keys {
        fmt.Println("Key:", k, "Value:", m[k])
    }
}

आउटपुट:

Key: 0 Value: b
Key: 1 Value: a
Key: 2 Value: c

38
इसके साथ सुधार किया जा सकता है keys := make([]int, len(m))और फिर इंडेक्स द्वारा keys[i] = kappend
डाला

18

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

फिर आपको क्या करना है, चाबियों को एक स्लाइस में खींचना है, उन्हें क्रमबद्ध करना है, और फिर इस तरह से स्लाइस पर रेंज करें:

var m map[keyType]valueType
keys := sliceOfKeys(m) // you'll have to implement this
for _, k := range keys {
    v := m[k]
    // k is the key and v is the value; do your computation here
}

प्रतीक्षा स्लाइस एक सरणी के भाग हैं। मैं नक्शे में केवल कुंजियों का एक टुकड़ा कैसे बनाऊं?
gramme.ninja

1
गो में, शब्द "स्लाइस" एक डेटा संरचना को संदर्भित करता है जो अनिवार्य रूप से जावा सरणियों के अनुरूप है। यह सिर्फ एक शब्दावली का मुद्दा है। कुंजियाँ प्राप्त करने के लिए, आपको मानचित्र पर स्पष्ट रूप से श्रेणी बनानी होगी और
joshlf

आह ठीक है। मुझे पढ़ाने के लिए धन्यवाद। अब, यह सभी को प्रिंट कर रहा है फिर भी सभी विषम हैं। play.golang.org/p/K2y3m4Zzqd मैं इसे वैकल्पिक रूप से कैसे प्राप्त कर सकता हूं ताकि यह क्रम में हो?
gramme.ninja

1
आपको उस स्लाइस को छाँटने की ज़रूरत होगी जो आपको वापस मिलती है (या, वैकल्पिक रूप से, इसे मैप में छाँटें। लौटने से पहले)। आप सॉर्ट पैकेज देखना चाहेंगे ।
3

14

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

func main() {
    m := map[int]int{3: 5, 2: 4, 1: 3}
    fmt.Println(m)

    // In Go 1.12+
    // Output: map[1:3 2:4 3:5]

    // Before Go 1.12 (the order was undefined)
    // map[3:5 2:4 1:3]
}

परीक्षण को आसान बनाने के लिए मानचित्र अब कुंजी-क्रमबद्ध क्रम में मुद्रित होते हैं। आदेश देने के नियम हैं:

  • लागू होने पर, शून्य कम तुलना करता है
  • इन्टस, फ्लोट्स और स्ट्रिंग्स ऑर्डर <द्वारा
  • NaN की तुलना गैर-NaN फ़्लोट्स से कम है
  • बूल सच से पहले झूठ की तुलना करता है
  • कॉम्प्लेक्स असली, फिर काल्पनिक की तुलना करता है
  • पॉइंटर्स मशीन के पते से तुलना करते हैं
  • चैनल मान मशीन के पते से तुलना करते हैं
  • संरचनाएं बदले में प्रत्येक क्षेत्र की तुलना करती हैं
  • Arrays बदले में प्रत्येक तत्व की तुलना करते हैं
  • इंटरफ़ेस मान पहले परावर्तित करके तुलना करते हैं। पिछले नियमों में वर्णित कंक्रीट प्रकार और फिर ठोस मूल्य का वर्णन करते हुए।

मैप्स को प्रिंट करते समय, NaN जैसे गैर-रिफ्लेक्सिव प्रमुख मान पहले प्रदर्शित किए गए थे <nil>। इस रिलीज के अनुसार, सही मान छपे हैं।

और अधिक पढ़ें यहाँ


8
यह केवल fmt पैकेज और प्रिंटिंग पर लागू होता है। प्रश्न यह पूछता है कि मानचित्र को कैसे छाँटना है, छँटे हुए मानचित्र को कैसे प्रिंट नहीं करना है?
टिम

1
उन्होंने एक खेल का मैदान लिंक साझा किया। वहाँ वह सिर्फ एक नक्शा प्रिंट करता है।
इनक गमूस

2

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

मुख्य प्रकार Kऔर मूल्य प्रकार के साथ एक मानचित्र को देखते हुए V, जैसा कि नीचे <K>और <V>नीचे दर्शाया गया है, आम प्रकार फ़ंक्शन इस गो-कोड टेम्प्लेट की तरह लग सकता है (जो कि गो संस्करण 1 के रूप में समर्थन नहीं करता है):

/* Go apparently doesn't support/allow 'interface{}' as the value (or
/* key) of a map such that any arbitrary type can be substituted at
/* run time, so several of these nearly-identical functions might be
/* needed for different key/value type combinations. */
func sortedMap<K><T>(m map[<K>]<V>, f func(k <K>, v <V>)) {
    var keys []<K>
    for k, _ := range m {
        keys = append(keys, k)
    }
    sort.Strings(keys)  # or sort.Ints(keys), sort.Sort(...), etc., per <K>
    for _, k := range keys {
        v := m[k]
        f(k, v)
    }
}

फिर इसे इनपुट मानचित्र और एक फ़ंक्शन ( (k <K>, v <V>)इसके इनपुट तर्कों के रूप में) के साथ कॉल करें , जिसे सॉर्ट-कुंजी क्रम में मैप तत्वों पर कहा जाता है।

तो, Mingu द्वारा पोस्ट किए गए उत्तर में कोड का एक संस्करण जैसा दिख सकता है:

package main

import (
    "fmt"
    "sort"
)

func sortedMapIntString(m map[int]string, f func(k int, v string)) {
    var keys []int
    for k, _ := range m {
        keys = append(keys, k)
    }
    sort.Ints(keys)
    for _, k := range keys {
        f(k, m[k])
    }
}

func main() {
    // Create a map for processing
    m := make(map[int]string)
    m[1] = "a"
    m[2] = "c"
    m[0] = "b"

    sortedMapIntString(m,
        func(k int, v string) { fmt.Println("Key:", k, "Value:", v) })
}

sortedMapIntString()समारोह किसी के लिए पुन: उपयोग किए जा सकता है map[int]string(यह मानते हुए एक ही सॉर्ट क्रम वांछित है), कोड की सिर्फ दो लाइनों के लिए प्रत्येक उपयोग के रखे हुए हैं।

डाउनसाइड में शामिल हैं:

  • प्रथम श्रेणी के कार्यों का उपयोग करने के लिए बेहिसाब लोगों के लिए पढ़ना कठिन है
  • यह धीमा हो सकता है (मैंने प्रदर्शन तुलना नहीं की है)

अन्य भाषाओं में विभिन्न समाधान हैं:

  • यदि ( <K>और <V>कुंजी और मूल्य के प्रकारों को निरूपित करने के लिए) का उपयोग थोड़ा परिचित है, तो यह कोड टेम्प्लेट + ++ टेम्प्लेट के विपरीत नहीं है।
  • क्लोजर और अन्य भाषाएं मौलिक डेटा प्रकारों के रूप में छांटे गए मानचित्रों का समर्थन करती हैं।
  • हालांकि मुझे किसी भी तरह से पता नहीं है कि गो rangeएक प्रथम श्रेणी का प्रकार बनाता है, जिसे कस्टम ordered-range( rangeमूल कोड के स्थान पर) के साथ प्रतिस्थापित किया जा सकता है , मुझे लगता है कि कुछ अन्य भाषाएं पुनरावृत्त प्रदान करती हैं जो समान पूरा करने के लिए पर्याप्त शक्तिशाली हैं चीज़।

2
यह शुरुआती लोगों के लिए इंगित करने योग्य हो सकता है, कि गो में <K>, <V> सिंटैक्स समर्थित नहीं है।
justinhj

2

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

उदाहरण:

package main

import (
    "fmt"
    "sort"
)

type myIntMap map[int]string

func (m myIntMap) sort() (index []int) {
    for k, _ := range m {
        index = append(index, k)
    }
    sort.Ints(index)
    return
}

func main() {
    m := myIntMap{
        1:  "one",
        11: "eleven",
        3:  "three",
    }
    for _, k := range m.sort() {
        fmt.Println(m[k])
    }
}

कई मानचित्र प्रकारों के साथ विस्तारित खेल का मैदान उदाहरण

महत्वपूर्ण लेख

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

mutex.Lock()
for _, k := range m.sort() {
    fmt.Println(m[k])
}
mutex.Unlock()

0

यह आपको मानचित्रण के लिए कोड उदाहरण प्रदान करता है। मूल रूप से यह वही है जो वे प्रदान करते हैं:

var keys []int
for k := range myMap {
    keys = append(keys, k)
}
sort.Ints(keys)

// Benchmark1-8      2863149           374 ns/op         152 B/op          5 allocs/op

और यह वही है जो मैं इसके बजाय उपयोग करने का सुझाव दूंगा :

keys := make([]int, 0, len(myMap))
for k := range myMap {
    keys = append(keys, k)
}
sort.Ints(keys)

// Benchmark2-8      5320446           230 ns/op          80 B/op          2 allocs/op

इस गो प्लेग्राउंड में पूरा कोड पाया जा सकता है ।

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