2013-06-18 3 views
4

이것은 훌륭한 "왜 맵 프린트가 순서가 틀린 것인가"라는 질문의 변형입니다.지도를 순서대로 반복 할 수있는 쉬운 방법이 있습니까?

map[MyKey]MyValue 형태의지도가 상당히 많습니다. MyKeyMyValue은 (일반적으로) 구조체입니다. 모든 키 유형에 대해 "적은"기능을 제공합니다.

지도를 순서대로 반복해야합니다. (. 특히, 순서는 해당 유형에 덜 함수로 정의) 지금, 내 코드는 다음과 같습니다 : 다음

type PairKeyValue struct { 
    MyKey 
    MyValue 
} 

type PairKeyValueSlice []Pair 

func (ps PairKeyValueSlice) Len() int { 
    return len(ps) 
} 

func (ps PairKeyValueSlice) Swap(i,j int) { 
    ps[i], ps[j] = ps[j], ps[i] 
} 

func (ps PairKeyValueSlice) Less(i,j int) { 
    return LessKey(ps[i].MyKey, ps[j].MyKey) 
} 

func NewPairKeyValueSlice(m map[MyKey]MyValue) (ps PairKeyValueSlice) { 
    ps = make(PairKeyValueSlice, len(m)) 
    i := 0 
    for k,v := range m { 
     ps[i] = PairKeyValue{k,v} 
     i++ 
    } 
    sort.Sort(ps) 
} 

그리고, 내가의 순서 반복을 원하는 시간, 그것은 같이 보인다 :

var m map[MyKey]MyValue 
m = GetMapFromSomewhereUseful() 
for _, kv := range NewPairKeyValueSlice(m) { 
    key := kv.MyKey 
    value := kv.MyValue 
    DoUsefulWork(key, value) 
} 

그리고 이것은 크게 작용하는 것처럼 보입니다. 문제는 그것이 매우 상세하다는 것입니다. 특히 수작업으로 발생하는 문제는 지시 된 맵을 함축하는 것과 거의 관련이 없으므로 실제로 루프의 유용한 작업에 관한 것입니다.

또한 여러 가지 키와 값 유형이 있습니다. 따라서 순서대로 맵을 반복 할 때마다 모든 코드를 복사/붙여 넣기하고 MyKey을 새 키로 바꾸거나 MyValue을 새 값으로 바꾸거나 바꾸십시오. 그 크기의 복사/붙여 넣기는 ... "냄새 나는". 이미 여러 번 오류를 수정했기 때문에 이미 번거 로움이 있습니다.

이 기술은 또한 모든 키와 값의 전체 복사본을 만들어야한다는 단점이 있습니다. 그건 바람직하지 않지만, 나는 그 주위에 방법이 보이지 않는다. (키로 만 줄일 수는 있지만 문제의 주요 특성은 바뀌지 않습니다.)

This question은 문자열과 동일한 것을 시도하고 있습니다. This question은 문자열과 int로 처리합니다. This question은 리플렉션을 사용해야 함을 의미하며 모든 사용자 정의 유형을 포함하여 가능한 모든 유형을 전환하는 switch 문을 가져야합니다.

그러나지도가 결정 론적으로 반복되지 않는다는 당혹감을 가진 사람들과 함께이 문제에 대한 더 나은 해결책이있는 것으로 보입니다. 나는 OO 백그라운드에서 왔으므로 근본적으로 뭔가 빠졌을 것입니다.

그래서 맵을 순서대로 반복하는 방법이 있습니까?


업데이트 : 이것보다 더 나은 솔루션있을 경우 소스에 대한 자세한 정보를 가지고 질문을 편집.

나는 출력을 위해 그룹화해야 할 많은 것들이 있습니다.

type ObjTypeTree struct { 
    Children map[Type]*ObjKindTree 
    TotalCount uint 
} 
type ObjKindTree struct { 
    Children map[Kind]*ObjAreaTree 
    TotalCount uint 
} 
type ObjAreaTree struct { 
    Children map[Area]*ObjAreaTree 
    TotalCount uint 
    Objs []*Obj 
} 

그럼,이 유형의 그룹을 인쇄 할 ObjTypeTree의 자식들에 대해 반복 것 : 각 그룹화 수준은 다음과 같은 구조입니다. 각각의 경우에 대해 ObjKindTree을 반복하여 종류 그룹을 인쇄합니다. 반복은 유형에 대한 메소드로 수행되며 각 유형의 유형은 그룹화 레벨을 인쇄하는 약간 다른 방법이 필요합니다. 그룹을 순서대로 인쇄해야 문제가 발생합니다.

+1

정말 나쁜 해결책에 대해 우리 모두에게 말했습니다. 해결할 문제를 알려주십시오. 그러면 좋은 해결책을 제안 할 수 있습니다. – peterSO

+0

그래, 해결하려고하는 문제에 대한 일부 정보를 편집했습니다. – alficles

답변

2

키 조합이 필요한 경우 맵을 사용하지 마십시오. B 트리 또는 기타/유사 컨테이너로 주문하십시오.

+1

그건 생각해 봤지만 동일한 카피/페이스트 문제가 생기지 않았습니까? 제가 포함 할 수있는 각각의 타입에 대해 동일한 주문 컨테이너를 한 번 다시 임 플레멘 테이션하는 것일까 요? 타입 안전성을 없애기 위해 인터페이스 {}를 사용할 수있는 방법이 있을지 모르지만 그게 문제입니다. – alficles

+2

[some] (https://github.com/datastream/btree) [libraries] (https://github.com/runningwild/go-btree) [사용할 수 있습니다] (https://github.com)/stathat/treap)이 문제를 이미 해결해 줬습니다. :) 그 중 하나는 gotgo를 사용하는 것입니다 - 어느 정도 - 의사 - 제네릭을 제공하는 전처리 기입니다. 그래서, 만약 당신이 모험심을 느끼고 있다면 ... – nemo

+0

흠, 더 많은 것을 찾고 있습니다. 저는 이것을하기 위해 타입 시스템을 물리 칠 필요가 있습니다. (또는 전처리기를 사용하고, 어느 것이 더 나쁘지는 모르겠다.) 나는 다른 대답을 기대하고 있었다. – alficles

2

두 번째 jnml의 답변입니다. 그러나 당신이 가지고있는 것보다 더 짧은 것을 원하고 컴파일 타임 타입 안전을 기꺼이 포기하고자한다면 my library이 도움이 될 것입니다. (. 그것은 reflect 위에 구축 된 것) 여기에 전체 작업 예제 :

package main 

import (
    "fmt" 

    "github.com/BurntSushi/ty/fun" 
) 

type OrderedKey struct { 
    L1 rune 
    L2 rune 
} 

func (k1 OrderedKey) Less(k2 OrderedKey) bool { 
    return k1.L1 < k2.L1 || (k1.L1 == k2.L1 && k1.L2 < k2.L2) 
} 

func main() { 
    m := map[OrderedKey]string{ 
     OrderedKey{'b', 'a'}: "second", 
     OrderedKey{'x', 'y'}: "fourth", 
     OrderedKey{'x', 'x'}: "third", 
     OrderedKey{'a', 'b'}: "first", 
     OrderedKey{'x', 'z'}: "fifth", 
    } 

    for k, v := range m { 
     fmt.Printf("(%c, %c): %s\n", k.L1, k.L2, v) 
    } 
    fmt.Println("-----------------------------") 

    keys := fun.QuickSort(OrderedKey.Less, fun.Keys(m)).([]OrderedKey) 
    for _, k := range keys { 
     v := m[k] 
     fmt.Printf("(%c, %c): %s\n", k.L1, k.L2, v) 
    } 
} 

참고 이러한 방법이 느린 것, 그래서 당신은 성능을 필요로하는 경우, 이것은 좋은 선택이 아니다.

관련 문제