LoginSignup
0
0

More than 3 years have passed since last update.

【C#,Unity】Dictionary<GameObject,float>をfloat基準で昇順にSortしようとしたら謎処理を挟んでいた話

Last updated at Posted at 2019-11-15

追記【2019/11/15】

@albireo 様にアドバイスしていただいたSortedListの方が簡易的かつ無駄なく処理できたので
記事の末尾に追加しておきました。

この記事の狙い

自分の経験を書き記すとともに、有識者の方々からアドバイスや説明をもらえたらいいなぁ。
という期待。

あらすじ

Unityで画面内に映っているTargetを取得&自キャラとTargetの距離を取得できるようになったので、
これを「距離が近い順」で並べ替えたい!と思い、色々調べながら試してみることに。

本題

まず「画面内に映っているTarget」と「Targetまでの距離」、この二つの情報を紐付けるには
どうすればいいのかを調べるところから始めた。

これは調べると直ぐに出てきた、最初はList<>か配列[ ]でなんとかするしかないのかな?とか考えていたが、
調べてみるとDictionaryという超便利なクラスがあるではないか。
早速、意気揚々と使ってみる。

Dictionary<GameObject,float> ProvisionalValue = new Dictionary<GameObject,float>();
ProvisionalValue.Add(hit,target_distance); 

よし、これで情報の紐付けはできたな...!
後はこれを「距離が近い順」で並べ替えるだけだ...!

なんだ楽勝じゃん。勝ったな、風呂入ってくる。

ここからが本当の地獄だ...!

さて、ちゃちゃっとSortして終わらせるか~

ProvisionalValue.Sort();

...あれ、できない。なになに?DictionaryにはSortの定義が含まれていない?
あら、そうなのか...。じゃあどうやって並び替えするんだろう、調べてみるか...。

【C#入門】DictionaryのKey、Valueの使い方(要素の追加、取得も解説)

ははーん、Linqを使えば出来るのね。試したことが無いけど、やってみるか...。

ここで訳の分からないことをし始める(多分色々調べているうちにいろんな記事の情報が入り混じった)

えーっと、まずはソートする基準がいるから(?)floatだけをList<>で取得してからこれをOrderByで
並べ替えて...、あれ?Valueが定義が含まれていない...?(Listだから)

これは何かがおかしい...!という感じで混迷を極めた結果、こうなった。

    private static Dictionary<GameObject,float> hitsOB = new Dictionary<GameObject,float>();
    private static Dictionary<GameObject,float> ProvisionalValue = new Dictionary<GameObject,float>();

    {
        ProvisionalValue.Add(hit,target_distance);
        Sort(ProvisionalValue);
    }

    public static void Sort(Dictionary<GameObject,float> itemTable) //取得したオブジェクトと距離のデータを距離が近い順でソートするメソッド
    {
        IOrderedEnumerable<KeyValuePair<GameObject,float>> _table_1 =
            itemTable.OrderBy(selector => selector.Value);
            foreach(KeyValuePair<GameObject,float> pair in _table_1)
            {
                hitsOB.Add(pair.Key,pair.Value);
            }
    }

改めて見ると何やってるんだか、と思いました。

ProvisionalValueに格納したデータをOrderByで並べ替えて、並べ替えたデータを_table_1に格納して、
foreachでpairに一つずつ格納してhitsOBに順に格納....

いや、これ普通にProvisionalValueをOrderByでソートすればいいじゃん。

はい、というわけでそうした結果がこちら。

ProvisionalValue.Add(hit,target_distance);
ProvisionalValue.OrderBy(x => x.Value);

二行で終了。(なぜ俺はあんなムダな時間を...)

ふりかえり

そもそも混乱した理由は「よく理解していなかったから」につきます。
Dictionaryの値の取得方法すら理解していなかったが為に、KeyとValueがなんなのか分からずに使っていた
結果、今回のような無駄な時間を浪費する羽目になりました...。

まさしく「知識は身を助ける」を身をもって実感しました。

追加記事【SortedList】

先に紹介したDictionaryクラスは値を格納した後にOrderByでソートしていましたが、
SortedListクラスを使用すればわざわざソートする必要がなくなります。

しかし、注意しなければいけない点があります。
それはSortedList <TKey,TValue>では、キー(TKey)の値を基準にソートされます。

今回の例で行くと、先の紹介したDictionaryはDictionary<GameObject,float>としていましたが、
これだとTKeyの値に代入しているGameObjectのソート基準はNameの頭文字をABCD...順で並び替える為、
ソートの基準は距離で並び替えたかったので、順番を入れ替える必要がありました。

ということを踏まえた上で変更したものが以下の流れです。(距離の所得等は省いています)

private SortedList<float,GameObject> ProvisionalValue;

void Start()
{
   ProvisionalValue = new SortedList<float,GameObject>();
}
public void Sort()
{
   ProvisionalValue.Add(target_distance,hit);
   foreach(var item in ProvisionalValue)
   {
       Debug.Log("Distance : " + item.Key + " / Object : " + item.Value);
   }
}

これでコンソールに距離順で距離とオブジェクト名が表示されます。

0
0
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0