একটি মানচিত্র থেকে চাবি একটি স্লাইস পেয়ে


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)
    }
}

Go এ দক্ষ হওয়ার জন্য, মেমরির বরাদ্দকে হ্রাস করতে গুরুত্বপূর্ণ।


29
সামর্থ্যের পরিবর্তে প্রকৃত আকার নির্ধারণ করা এবং পুরোপুরি সংযোজন এড়ানো ভাল slightly বিস্তারিত জানার জন্য আমার উত্তর দেখুন।
বিনয় পাই

3
মনে রাখবেন যে যদি mymapস্থানীয় পরিবর্তনশীল না হয় (এবং তাই এটি বৃদ্ধি / সংকোচনের সাপেক্ষে) তবে এটিই একমাত্র সঠিক সমাধান - এটি নিশ্চিত করে যে যদি mymapআরম্ভের keysএবং forলুপের মধ্যে পরিবর্তনগুলির আকার হয় তবে কোনও আউট- সীমাবদ্ধ সমস্যা।
মেল্লাওয়ার

12
একযোগে অ্যাক্সেসের অধীনে মানচিত্রগুলি নিরাপদ নয়, অন্য কোনও গরোটিন মানচিত্র পরিবর্তন করতে পারে তবে কোনও সমাধানই গ্রহণযোগ্য নয়।
বিনয় পাই

@ বিনয়পাই একাধিক গোরোটাইন থেকে মানচিত্র থেকে পড়া ঠিক আছে তবে লিখছেন না
দার্থেস

@ দেদারহস যা একটি সাধারণ ভুল ধারণা। রেস ডিটেক্টর ১.6 থেকে এই ব্যবহারটিকে পতাকাঙ্কিত করবে। রিলিজের নোট থেকে: "বরাবরের মতো, যদি কোনও গোরোটিন কোনও মানচিত্রে লিখতে থাকে তবে অন্য কোনও গুরোটিন একই সাথে মানচিত্রটি পড়তে বা লিখতে হবে না the golang.org/doc/go1.6# রুনটাইম
বিনয় পাই

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{,। এইভাবে আপনার আই ++ লাগবে না?
এমভানডাই

30
হতে পারে আমি এখানে কিছু মিস করছি, তবে আপনি যদি তা করেন i, k := range mymapতবে iকীগুলি kহবে এবং মানচিত্রের সেই কীগুলির সাথে সম্পর্কিত মান হবে। এটি আপনাকে কীগুলির একটি স্লাইস পপুলেট করতে সহায়তা করবে না।
বিনয় পাই

4
@ আলাস্কা যদি আপনি একটি অস্থায়ী কাউন্টার ভেরিয়েবল বরাদ্দের ব্যয় নিয়ে উদ্বিগ্ন হন তবে মনে করেন কোনও ফাংশন কল কম স্মৃতি গ্রহণ করছে যা কোনও ফাংশন ডাকা হয়ে গেলে আসলে কী ঘটে সে সম্পর্কে আপনার নিজেকে শিক্ষিত করা উচিত। ইঙ্গিত: এটি কোনও magন্দ্রজালিক উদ্দীপনা নয় যা বিনামূল্যে কাজ করে। আপনি যদি মনে করেন বর্তমানে গৃহীত উত্তরগুলি সমবর্তী অ্যাক্সেসের অধীনে নিরাপদ, তবে আপনাকে আবার বেসিকগুলিতেও ফিরে যেতে হবে: blog.golang.org/go-maps-in-action#TOC_6
বিনয় পাই

79

আপনি প্যাকেজ "প্রতিচ্ছবি" থেকে স্ট্রাক্ট []Valueপদ্ধতি MapKeysঅনুসারে কীগুলির একটি অ্যারেও নিতে পারেন 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
আমি মনে করি যদি সমবর্তী মানচিত্রের অ্যাক্সেসের সুযোগ থাকে তবে এটি একটি ভাল পদ্ধতি: লুপ চলাকালীন মানচিত্রটি বাড়লে এটি আতঙ্কিত হবে না। পারফরম্যান্স সম্পর্কে, আমি সত্যই নিশ্চিত নই, তবে আমার সন্দেহ হয় যে এটি পরিশিষ্টের সমাধানটিকে ছাড়িয়ে যায়।
আতিলা রোমেরো

@ আতিলারোমেরো নিশ্চিত নয় যে এই সমাধানটির কোনও সুবিধা রয়েছে তবে কোনও উদ্দেশ্যে প্রতিচ্ছবি ব্যবহার করার সময় এটি আরও কার্যকর, কারণ এটি সরাসরি টাইপ করা মান হিসাবে কীটি গ্রহণ করতে দেয়।
ডেনিস ক্রেশিখিন

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)), যা আমার জন্য সেই ক্রিয়াকলাপটির পারফরম্যান্সকে মারাত্মকভাবে পরিবর্তন করেছে।
কিথভুন্টার

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.