4

これは、由緒ある「なぜ私の地図が正しく印刷されないのか」という質問の変形です。

私は (かなり多数の) 形式のマップを持っています。 map[MyKey]MyValuewhereMyKeyMyValueare (通常) 構造体です。すべてのキータイプに対して「少ない」機能があります。

マップを順番に反復処理する必要があります。(具体的には、その型の less 関数によって定義された順序です。) 現在、私のコードは次のようになっています。

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新しい値で検索/置換します。そのマグニチュードをコピペすると…「臭い」。何度か修正しなければならなかったいくつかのエラーをすでに作成しているため、すでに面倒になっています。

この手法には、すべてのキーと値の完全なコピーを作成する必要があるという欠点もあります。それは望ましくありませんが、それを回避する方法がわかりません。(キーだけに減らすこともできますが、問題の本質は変わりません。)

この質問は、文字列で同じことを試みています。この質問は、文字列と整数でそれを行います。この質問は、リフレクションを使用する必要があり、すべてのユーザー定義型を含むすべての可能な型をオンにする switch ステートメントが必要であることを意味します。

しかし、マップが決定論的に繰り返されないことに当惑している人々にとっては、この問題に対するより良い解決策が必要であると思われます。私はオブジェクト指向のバックグラウンドを持っているので、おそらく何か基本的なことが欠けています。

では、マップを順番に反復処理する合理的な方法はありますか?


更新:これよりも優れた解決策がある場合に備えて、ソースに関する詳細情報を得るために質問を編集します。

出力のためにグループ化する必要があるものがたくさんあります。各グループ化レベルは、次のような構造になっています。

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、Type グループを出力します。それらのそれぞれについて、 を繰り返し処理しObjKindTreeて Kind グループを出力します。反復は型のメソッドで行われ、型の種類ごとにグループ化レベルを出力する方法が少し異なります。グループを順番に印刷する必要があるため、問題が発生します。

4

2 に答える 2

2

キーの照合が必要な場合は、マップを使用しないでください。B ツリーまたはその他の/類似の順序付きコンテナーを使用します。

于 2013-06-18T22:40:25.573 に答える
2

私は2番目のjnmlの答えです。しかし、あなたが持っているものよりも短いものが必要で、コンパイル時の型の安全性を放棄しても構わないと思っているなら、私のライブラリがあなたのために働くかもしれません. (これは の上に構築されてい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)
    }
}

このような方法は遅くなるため、パフォーマンスが必要な場合は、これは適切な選択ではないことに注意してください。

于 2013-06-19T16:56:09.310 に答える