गोलंग में मानचित्र से मानों का एक टुकड़ा प्राप्त करने का एक अच्छा तरीका है?


90

अगर मेरे पास एक मानचित्र है तो वहाँ मूल्यों का एक टुकड़ा प्राप्त करने का एक बेहतर तरीका v है

package main
import (
  "fmt"
)

func main() {
    m := make(map[int]string)

    m[1] = "a"
    m[2] = "b"
    m[3] = "c"
    m[4] = "d"

    // Can this be done better?
    v := make([]string, len(m), len(m))
    idx := 0
    for  _, value := range m {
       v[idx] = value
       idx++
    }

    fmt.Println(v)
 }

क्या एक नक्शे की निर्मित सुविधा है? क्या गो पैकेज में कोई फ़ंक्शन है, या क्या मुझे करना है तो यह सबसे अच्छा कोड है?


1
लूप के लिए '_' के बजाय, इसे आईडीएक्स कॉल करें और आईडीएक्स + व्यापार को खोदें
पीटर एग्न्यू

नहीं, वह नहीं कर सकता है, जब आप एक नक्शे पर रेंज करते हैं तो यह कुंजी देता है, मूल्य सूचकांक नहीं, मूल्य। अपने उदाहरण में वह पहली कुंजी के रूप में 1 का उपयोग करता है और यह स्लाइस v में इंडेक्स को गलत बना देगा क्योंकि स्टार्ट इंडेक्स 1 नहीं शून्य होगा, और जब यह 4 हो जाता है तो यह सीमा से बाहर हो जाएगा। play.golang.org/p/X8_SbgxK4VX
पोपमेडिक

@Popmedic वास्तव में, हाँ वह कर सकता है। बस के _साथ बदलें idxऔर उपयोग करें idx-1जब टुकड़ा मान असाइन करें।
hewiefreeman

3
@ newplayer66, यह एक बहुत ही खतरनाक पैटर्न है।
पोपमेडिक

जवाबों:


60

दुर्भाग्यवश नहीं। ऐसा करने का कोई बिलकुल तरीका नहीं है।

एक साइड नोट के रूप में, आप अपने स्लाइस निर्माण में क्षमता तर्क को छोड़ सकते हैं:

v := make([]string, len(m))

क्षमता का तात्पर्य यहाँ की लंबाई के समान होना है।


1
मुझे लगता है कि एक बेहतर तरीका है: stackoverflow.com/a/61953291/1162217
लुकास लुकाक

58

Jimt के पद के अतिरिक्त:

आप appendउनके सूचकांकों को मान देने के बजाय स्पष्ट रूप से उपयोग कर सकते हैं :

m := make(map[int]string)

m[1] = "a"
m[2] = "b"
m[3] = "c"
m[4] = "d"

v := make([]string, 0, len(m))

for  _, value := range m {
   v = append(v, value)
}

ध्यान दें कि लंबाई शून्य है (अभी तक कोई तत्व मौजूद नहीं है) लेकिन क्षमता (आवंटित स्थान) के तत्वों की संख्या के साथ आरंभीकृत है m। ऐसा इसलिए किया जाता है ताकि appendहर बार स्लाइस की क्षमता vसमाप्त हो जाने पर मेमोरी आवंटित करने की आवश्यकता न हो।

आप makeक्षमता मान के बिना भी स्लाइस कर सकते हैं और अपने appendलिए मेमोरी आवंटित कर सकते हैं।


मैं सोच रहा था कि क्या यह कोई धीमा होगा (सामने आवंटन को देखते हुए)? मैंने एक मानचित्र [इंट] इंट के साथ एक कच्चा बेंचमार्क किया और यह लगभग 1-2% धीमा लग रहा था। किसी भी विचार अगर यह चिंता करने के लिए कुछ है या बस इसके साथ जाना है?
मस्सेब

1
मुझे लगता है कि यह थोड़ा धीमा होगा, लेकिन यह अंतर ज्यादातर मामलों में नगण्य है। बेंचमार्क प्रत्यक्ष असाइनमेंट और परिशिष्ट की तुलना
nemo

1
ऊपर दिए गए उत्तर के साथ इसे मिश्रण करने में सावधानी बरतें - आपके द्वारा उपयोग किए जाने के बाद सरणी में make([]appsv1.Deployment, len(d))संलग्न होने पर खाली तत्वों का एक गुच्छा होगा जो आपको len(d)खाली आइटम आवंटित किए जाने पर बनाए गए थे ।
अनिरुद्ध रामनाथन

2

जरूरी नहीं कि बेहतर हो, लेकिन ऐसा करने का क्लीनर तरीका स्लाइस लेंथ और क्षमता दोनों को परिभाषित करके हैtxs := make([]Tx, 0, len(txMap))

    // Defines the Slice capacity to match the Map elements count
    txs := make([]Tx, 0, len(txMap))

    for _, tx := range txMap {
        txs = append(txs, tx)
    }

पूर्ण उदाहरण:

package main

import (
    "github.com/davecgh/go-spew/spew"
)

type Tx struct {
    from  string
    to    string
    value uint64
}

func main() {
    // Extra touch pre-defining the Map length to avoid reallocation
    txMap := make(map[string]Tx, 3)
    txMap["tx1"] = Tx{"andrej", "babayaga", 10}
    txMap["tx2"] = Tx{"andrej", "babayaga", 20}
    txMap["tx3"] = Tx{"andrej", "babayaga", 30}

    txSlice := getTXsAsSlice(txMap)
    spew.Dump(txSlice)
}

func getTXsAsSlice(txMap map[string]Tx) []Tx {
    // Defines the Slice capacity to match the Map elements count
    txs := make([]Tx, 0, len(txMap))
    for _, tx := range txMap {
        txs = append(txs, tx)
    }

    return txs
}

सरल समाधान लेकिन बहुत सारे गोच। अधिक जानकारी के लिए इस ब्लॉग पोस्ट को पढ़ें: https://web3.coach/golang-how-to-convert-map-to-slice-three-gotchas


उत्तर "गलत" नहीं है। प्रश्न सूचकांक का उपयोग करता है और स्लाइस के लिए कोई परिशिष्ट नहीं। यदि आप स्लाइस पर एपेंड का उपयोग करते हैं, तो हाँ सामने की तरफ लंबाई सेट करना बुरा होगा। यहाँ यह सवाल है क्योंकि यह play.golang.org/p/nsIlIl24Irn दी गयी है, यह सवाल मुहावरेदार नहीं है और मैं अभी भी सीख रहा था। थोड़ा और बेहतर संस्करण जो आप बात कर रहे हैं जैसे कि play.golang.org/p/4SKxC48wg2b
masebase

1
हाय @masebase, मैं इसे "गलत" मानता हूं क्योंकि यह बताता है: "दुर्भाग्य से, नहीं। ऐसा करने के लिए कोई बिल्टइन नहीं है।", लेकिन "बेहतर" समाधान है जो हम दोनों अब 2 साल बाद इंगित कर रहे हैं - एपेंड का उपयोग करना () और लंबाई और क्षमता दोनों को परिभाषित करना। लेकिन मैं आपकी बात देख रहा हूं कि इसे "गलत" कहना सही नहीं है। मैं अपना पहला वाक्य बदलूंगा: "जरूरी नहीं कि बेहतर हो, लेकिन ऐसा करने का क्लीनर तरीका है"। मैंने ~ 10 देवों से बात की है और सभी ने सहमति व्यक्त की है कि ऐप्पल () हेल्पर इंडेक्स का उपयोग किए बिना एक नक्शे को एक स्लाइस में बदलने के लिए एक क्लीनर तरीका है। मैंने इसे पोस्ट करने के तरीके पर भी सीखा
लुकास लुकाक

1

जहां तक ​​मुझे वर्तमान में पता है, कम से कम / दो / प्रतियां बनाये बिना एक परिणामी स्ट्रिंग में स्ट्रिंग्स / बाइट्स के संयोजन के लिए एक तरीका नहीं है।

वर्तमान में आपको एक [] बाइट का विकास करना है क्योंकि सभी स्ट्रिंग वैल्यू कांस्ट हैं, फिर भी आपको स्ट्रिंग बिल्डिन का उपयोग करना होगा भाषा को एक 'धन्य' स्ट्रिंग ऑब्जेक्ट बनाने के लिए, जिसे यह बफर कॉपी करेगा क्योंकि कुछ का कहीं संदर्भ हो सकता है [] बाइट के समर्थन में पता।

यदि एक [] बाइट उपयुक्त है, तो आप बाइट्स पर बहुत मामूली बढ़त हासिल कर सकते हैं। एक आवंटन करके और प्रतिलिपि बनाकर कार्य करें।

package main
import (
  "fmt"
)

func main() {
m := make(map[int]string)

m[1] = "a" ;    m[2] = "b" ;     m[3] = "c" ;    m[4] = "d"

ip := 0

/* If the elements of m are not all of fixed length you must use a method like this;
 * in that case also consider:
 * bytes.Join() and/or
 * strings.Join()
 * They are likely preferable for maintainability over small performance change.

for _, v := range m {
    ip += len(v)
}
*/

ip = len(m) * 1 // length of elements in m
r := make([]byte, ip, ip)
ip = 0
for  _, v := range m {
   ip += copy(r[ip:], v)
}

// r (return value) is currently a []byte, it mostly differs from 'string'
// in that it can be grown and has a different default fmt method.

fmt.Printf("%s\n", r)
}

1

आप इस mapsपैकेज का उपयोग कर सकते हैं :

go get https://github.com/drgrib/maps

फिर आपको बस कॉल करना है

values := maps.GetValuesIntString(m)

यह उस सामान्य mapसंयोजन के लिए सुरक्षित है । आप एक ही पैकेज में टूल generateका mapउपयोग करने वाले किसी अन्य प्रकार के लिए अन्य प्रकार-सुरक्षित कार्य कर सकते हैं mapper

पूर्ण प्रकटीकरण: मैं इस पैकेज का निर्माता हूं। मैंने इसे बनाया क्योंकि मैंने खुद को इन कार्यों को mapबार-बार लिखने के लिए पाया ।

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