7
6

More than 3 years have passed since last update.

多重Dictionaryをつくりたかった

Last updated at Posted at 2019-10-01

C#は素人なので定石がわかりません。

こういう連想配列があったとしましょう。

PHP
$datetimes = [
    'past' => [
        'yesterday' => new DateTime('yesterday'),
        'lastweek' => new DateTime('last week'),
    ],
    'future' => [
        'tomorrow' => new DateTime('tomorrow'),
        'nextyear' => new DateTime('next year'),
    ]
];

いや、こんな意味のわからない配列なんて作らねえよという抗議は全くもってその通りなのですがそこはスルーします。
実際はAPIに飛んできたリクエストをユーザ単位にまとめるみたいな処理をするところで、何個飛んでくるかわからないという仕様です。

PHPで書くとこんな感じでさくっとできます。

PHP
$datetimes = [];
foreach($request as $v){
    $datetimes[$v['tense']][$v['key']] = new DateTime($v['value']);
}

一瞬で書けてとってもらくちん。

ということで、この連想配列をC#に移植しようとしたのですが、どうもこのような構造について話をしているところがほとんど見当たりませんでした。
多重連想配列はC#では禁忌なのだろうか。

連想配列はDictionaryを使えばいいみたいですが、これは基本的に値がひとつです。
NameValueCollectionというのが目的に近かったのですが、これは値がstring固定みたいです。なぜ。
Microsoft.Experimental.Collectionsは名前が既に危ない。

試しにDictionaryの中にDictionaryを突っ込んでみたら普通にいけました。

    var datetimes = new Dictionary<string, Dictionary<string, DateTime>>();

    var list1 = new Dictionary<string, DateTime>();
    list1.Add("yesterday", new DateTime("yesterday"));
    list1.Add("lastweek", new DateTime("last week"));

    var list2 = new Dictionary<string, DateTime>();
    list2.Add("tomorrow", new DateTime("tomorrow"));
    list2.Add("nextyear", new DateTime("next year"));

    datetimes.Add("past", list1);
    datetimes.Add("future", list2);

ただ、この構造だとlist1などの中間変数が必要になってしまいます。
一気にdatetimes["past"].Add("yesterday", new DateTime("yesterday"));みたいなことはできないの?

    var datetimes = new Dictionary<string, Dictionary<string, DateTime>>();

    // The given key "past" was not present in the dictionary
    datetimes["past"].Add("yesterday", new DateTime("yesterday"));

    // Object reference not set to an instance of an object
    datetimes.Add("past", null);

    // An item with the same key has already been added
    datetimes.Add("past", new Dictionary<string, DateTime>{{"yesterday", new DateTime("yesterday")}} );
    datetimes.Add("past", new Dictionary<string, DateTime>{{"lastweek", new DateTime("last week")}} );

    // これはOK
    datetimes.Add("past", new Dictionary<string, DateTime>{{"yesterday", new DateTime("yesterday")}} );
    datetimes["past"].Add("lastweek", new DateTime("last week"));

Add自体はできるみたいですが、親Dictionaryのキーの有無によって動作を変えなければなりません。
キーが存在しない場合のみキーをAddし、その後はその中身だけAddしないといけないようです。
なんというかとても面倒。

もっとなんかマシな方法ってのがあるんだろうけどよくわかりませんでした。
そもそもC#ではどういう作りにするのが定石なんだろうか。

7
6
5

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
7
6