Nieco lepiej jest ustawić rzeczywisty rozmiar zamiast pojemności i całkowicie unikać dodawania. Zobacz moją odpowiedź, aby poznać szczegóły.
Vinay Pai,
3
Zauważ, że jeśli mymapnie jest zmienną lokalną (i dlatego podlega wzrostowi / zmniejszaniu), jest to jedyne właściwe rozwiązanie - zapewnia, że jeśli rozmiar mymapzmian między inicjalizacją keysi forpętlą nie będzie żadnych problemy z ograniczeniami.
Melllvar,
12
mapy nie są bezpieczne przy jednoczesnym dostępie, żadne rozwiązanie nie jest dopuszczalne, jeśli inny goroutine może zmienić mapę.
Vinay Pai,
@VayayPai można czytać na mapie z wielu goroutinów, ale nie pisać
darethas
@darethas, co jest powszechnym nieporozumieniem. Detektor wyścigu oznaczy to użycie od 1.6. Z informacji o wydaniu: „Jak zawsze, jeśli jeden goroutine pisze na mapie, żaden inny goroutine nie powinien jednocześnie czytać ani pisać mapy. Jeśli środowisko wykonawcze wykryje ten warunek, drukuje diagnozę i powoduje awarię programu”. golang.org/doc/go1.6#runtime
Vinay Pai
375
To stare pytanie, ale oto moje dwa centy. Odpowiedź PeterSO jest nieco bardziej zwięzła, ale nieco mniej wydajna. Wiesz już, jak duży będzie, więc nie musisz nawet używać append:
keys := make([]int, len(mymap))
i :=0for k := range mymap {
keys[i]= k
i++}
W większości sytuacji prawdopodobnie nie będzie to miało większego znaczenia, ale nie będzie to dużo więcej pracy, aw moich testach (przy użyciu mapy z 1 000 000 losowych int64kluczy, a następnie wygenerowaniu tablicy kluczy dziesięć razy przy każdej metodzie) chodziło o 20% szybciej, aby przypisać członków tablicy bezpośrednio niż użyć append.
Chociaż ustawienie pojemności eliminuje realokacje, append wciąż musi wykonać dodatkową pracę, aby sprawdzić, czy osiągnięto pojemność na każdym append.
To wygląda dokładnie tak samo jak kod OP. Zgadzam się, że to lepszy sposób, ale jestem ciekawy, czy nie zauważyłem różnicy między kodem tej odpowiedzi a kodem OP.
Emmaly Wilson,
4
Dobrze, że jakoś spojrzałem na inne odpowiedzi i przegapiłem, że moja odpowiedź jest dokładnie taka sama jak OP. No cóż, przynajmniej wiemy teraz w przybliżeniu, jaka jest kara za niepotrzebne użycie append :)
Vinay Pai,
5
Dlaczego nie używasz indeksu z zakresu, for i, k := range mymap{. W ten sposób nie potrzebujesz i ++?
mvndaai
30
Może czegoś mi brakuje, ale jeśli tak i, k := range mymap, to ibędą klucze i kbędą wartości odpowiadające tym kluczom na mapie. To naprawdę nie pomoże ci zapełnić kawałka kluczy.
Vinay Pai
4
@Alaska, jeśli martwisz się kosztem przydzielenia jednej tymczasowej zmiennej licznika, ale uważasz, że wywołanie funkcji zajmie mniej pamięci, powinieneś nauczyć się, co tak naprawdę dzieje się po wywołaniu funkcji. Wskazówka: To nie jest magiczne zaklęcie, które robi rzeczy za darmo. Jeśli uważasz, że obecnie akceptowana odpowiedź jest bezpieczna przy jednoczesnym dostępie, musisz także wrócić do podstaw: blog.golang.org/go-maps-in-action#TOC_6 .
Vinay Pai,
79
Możesz także pobrać tablicę kluczy typu za []Valuepomocą metody MapKeysstruct Valuez pakietu „reflect”:
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]}
Myślę, że jest to dobre podejście, jeśli istnieje szansa na równoczesny dostęp do mapy: nie panikuje, jeśli mapa powiększy się podczas pętli. Jeśli chodzi o wydajność, nie jestem do końca pewny, ale podejrzewam, że przewyższa ona dołączone rozwiązanie.
Atila Romero,
@AtilaRomero Nie jestem pewien, czy to rozwiązanie ma jakieś zalety, ale gdy używa się refleksji do jakichkolwiek celów, jest to bardziej przydatne, ponieważ pozwala wziąć klucz jako wartość wpisaną bezpośrednio.
Denis Kreshikhin,
10
Czy istnieje sposób na konwersję tego []string?
Doron Behar
14
Lepszym sposobem na to byłoby użycie append:
keys =[]int{}for k := range mymap {
keys = append(keys, k)}
Poza tym nie masz szczęścia - Go nie jest bardzo ekspresyjnym językiem.
Jest to jednak mniej wydajne niż oryginalne - append dokona wielu alokacji, aby powiększyć podstawową tablicę i musi aktualizować długość plasterka przy każdym wywołaniu. Powiedzenie keys = make([]int, 0, len(mymap))pozbędzie się alokacji, ale spodziewam się, że nadal będzie wolniejsze.
Nick Craig-Wood
1
Ta odpowiedź jest bezpieczniejsza niż użycie len (mymap), jeśli ktoś inny zmieni mapę podczas tworzenia kopii.
Atila Romero,
7
Zrobiłem szkicowy test porównawczy dla trzech metod opisanych w innych odpowiedziach.
Oczywiście wcześniejsze przydzielenie wycinka przed wyciągnięciem kluczy jest szybsze niż appending, ale, co zaskakujące, reflect.ValueOf(m).MapKeys()metoda jest znacznie wolniejsza niż ta ostatnia:
❯ go run scratch.go
populating
filling 100000000 slots
donein56.630774791s
running prealloc
took:9.989049786s
running append
took:18.948676741s
running reflect
took:25.50070649s
Oto kod: https://play.golang.org/p/Z8O6a2jyfTH
(uruchamianie go na boisku przerywa twierdzenie, że trwa to zbyt długo, więc cóż, uruchom go lokalnie.)
Odpowiedzi:
Na przykład,
Aby być wydajnym w Go, ważne jest, aby zminimalizować przydziały pamięci.
źródło
mymap
nie jest zmienną lokalną (i dlatego podlega wzrostowi / zmniejszaniu), jest to jedyne właściwe rozwiązanie - zapewnia, że jeśli rozmiarmymap
zmian między inicjalizacjąkeys
ifor
pętlą nie będzie żadnych problemy z ograniczeniami.To stare pytanie, ale oto moje dwa centy. Odpowiedź PeterSO jest nieco bardziej zwięzła, ale nieco mniej wydajna. Wiesz już, jak duży będzie, więc nie musisz nawet używać append:
W większości sytuacji prawdopodobnie nie będzie to miało większego znaczenia, ale nie będzie to dużo więcej pracy, aw moich testach (przy użyciu mapy z 1 000 000 losowych
int64
kluczy, a następnie wygenerowaniu tablicy kluczy dziesięć razy przy każdej metodzie) chodziło o 20% szybciej, aby przypisać członków tablicy bezpośrednio niż użyć append.Chociaż ustawienie pojemności eliminuje realokacje, append wciąż musi wykonać dodatkową pracę, aby sprawdzić, czy osiągnięto pojemność na każdym append.
źródło
for i, k := range mymap{
. W ten sposób nie potrzebujesz i ++?i, k := range mymap
, toi
będą klucze ik
będą wartości odpowiadające tym kluczom na mapie. To naprawdę nie pomoże ci zapełnić kawałka kluczy.Możesz także pobrać tablicę kluczy typu za
[]Value
pomocą metodyMapKeys
structValue
z pakietu „reflect”:źródło
[]string
?Lepszym sposobem na to byłoby użycie
append
:Poza tym nie masz szczęścia - Go nie jest bardzo ekspresyjnym językiem.
źródło
keys = make([]int, 0, len(mymap))
pozbędzie się alokacji, ale spodziewam się, że nadal będzie wolniejsze.Zrobiłem szkicowy test porównawczy dla trzech metod opisanych w innych odpowiedziach.
Oczywiście wcześniejsze przydzielenie wycinka przed wyciągnięciem kluczy jest szybsze niż
append
ing, ale, co zaskakujące,reflect.ValueOf(m).MapKeys()
metoda jest znacznie wolniejsza niż ta ostatnia:Oto kod: https://play.golang.org/p/Z8O6a2jyfTH (uruchamianie go na boisku przerywa twierdzenie, że trwa to zbyt długo, więc cóż, uruchom go lokalnie.)
źródło
keysAppend
funkcji możesz ustawić pojemnośćkeys
tablicymake([]uint64, 0, len(m))
, co drastycznie zmieniło dla mnie wydajność tej funkcji.Odwiedź https://play.golang.org/p/dx6PTtuBXQW
źródło