Improve this page Github へのログインが必要です。 簡単な修正は、ここから fork、オンライン編集、pull request ができます。 大きな修正については、 通常の clone で行って下さい。 Page wiki 関連するWikiページを参照・編集 English このページの英語版(原文)

連想配列

連想配列はindexが必ずしも整数である必要はなく、 疎なindexも扱えます。 連想配列のインデックスのことを key と呼び、その型を KeyTypeと呼びます。

連想配列は、 配列宣言の[]の中に KeyType を書いて宣言します:

int[string] b;    // 文字の配列で添え字づけられた
                  // int型の連想配列 b
                  // KeyType は string
b["hello"] = 3;   // key "hello" に値 3 を関連付ける
func(b["hello"]); // 3 を func() へ引数として渡す

連想配列のkeyは、 remove 関数によって取り除くことができます:

b.remove("hello");

InExpression によって、値がある連想配列のkeyであればその要素へのポインタ、 そうでなければ null が得られます:

int* p;
p = ("hello" in b);
if (p !is (B null))
        ...

関数型とvoidは KeyType にできません。

関数型とvoidは要素型にすることもできません。

クラスをKeyTypeとして使うには

クラスを KeyTypeとして使うこともできます。 そのためには、 クラスの定義で、以下にあげる Object のメンバ関数をオーバーライドしてください:

hash_t は整数型へのaliasです。

opCmpopEquals への引数の型はそのクラス自身ではなく、 Object 型とすることに注意が必要です。

例:

class Foo {
  int a, b;

  hash_t toHash() { return a + b; }

  bool opEquals(Object o)
  { Foo foo = cast(Foo) o;
    return foo && a == foo.a && b == foo.b;
  }

  int opCmp(Object o)
  { Foo foo = cast(Foo) o;
    if (!foo)
      return -1;
    if (a == foo.a)
      return b - foo.b;
    return a - foo.a;
  }
}

処理系は opEqualsopCmp、あるいはその両方のいずれかを使用します。 実装する際は、オブジェクト同士が等しいかどうかの判定に関しては opEqualsopCmp の結果が矛盾しないよう注意してください。

構造体や共用体をKeyTypeとして使うには

KeyType が構造体型の場合、 構造体のバイナリ表現を使ったハッシュ計算や比較が デフォルトの方式として使われます。 カスタマイズしたい場合は、 以下の関数を構造体のメンバとして提供します:

const hash_t toHash();
const bool opEquals(ref const KeyType s);
const int opCmp(ref const KeyType s);

例:

import std.string;

struct MyString {
  string str;

  const hash_t toHash()
  { hash_t hash;
    foreach (char c; str)
      hash = (hash * 9) + c;
    return hash;
  }

  const bool opEquals(ref const MyString s)
  {
    return std.string.cmp(this.str, s.str) == 0;
  }

  const int opCmp(ref const MyString s)
  {
    return std.string.cmp(this.str, s.str);
  }
}

処理系は opEqualsopCmp、あるいはその両方のいずれかを使用します。 実装する際は、オブジェクト同士が等しいかどうかの判定に関しては opEqualsopCmp の結果が矛盾しないよう注意してください。

プロパティ

連想配列のプロパティは以下の通りです:
連想配列のプロパティ
プロパティ 説明
.sizeof 連想配列への参照のサイズを返します。 32bitでは4で64bitでは8です。
.length 連想配列に格納された値の個数を返します。 動的配列とは異なり、読み取り専用です。
.keys 連想配列のkeyからなる 動的配列を返します。
.values 連想配列のvalueからなる 動的配列を返します。
.rehash 連想配列をin-placeで再構成し、より効率的なアクセスを可能にします。 rehashは、例えば、 プログラムがシンボルテーブルのロードを終えて、 さあ高速に参照したい、というときに効果があります。 返値は、再構成された配列自身です。
.byKey() ForeachStatement によって連想配列のkey全体をループするための delegateを返します。
.byValue() ForeachStatement によって連想配列のvalue全体をループするための delegateを返します。
.get(Key key, lazy Value defaultValue) key を連想配列から検索し、存在すれば対応する value を返し、 存在しなければ defaultValue を評価し値を返します。

連想配列の例: 単語数カウント

例では簡単のために、ファイルがASCIIでエンコードされLFで改行されているものとします。 汎用に書くには、dchar c をループに使い、 std.uni の関数を利用します。

import std.file;         // D のファイル I/O
import std.stdio;
import std.ascii;

void main (string[] args) {
  ulong totalWords, totalLines, totalChars;
  ulong[string] dictionary;

  writefln("   lines   words   bytes file");
  foreach (arg; args[1 .. $]) // 先頭以外の引数それぞれについて
  {
    ulong wordCount, lineCount, charCount;

    foreach(line; File(arg).byLine())
    {
      bool inWord;
      size_t wordStart;

      void tryFinishWord(size_t wordEnd)
      {
        if (inWord)
        {
          auto word = line[wordStart .. wordEnd];
          ++dictionary[word.idup];   // 単語数をカウントアップ
          inWord = false;
        }
      }

      foreach (i, char c; line)
      {
        if (std.ascii.isDigit(c))
        { // c は数字 (0..9)
        }
        else if (std.ascii.isAlpha(c))
        { // c はASCII文字 (A..Z, a..z)
          if (!inWord)
          {
            wordStart = i;
            inWord = true;
            ++wordCount;
          }
        }
        else
          tryFinishWord(i);
        ++charCount;
      }
      tryFinishWord(line.length);
      ++lineCount;
    }

    writefln("%8s%8s%8s %s", lineCount, wordCount, charCount, arg);
    totalWords += wordCount;
    totalLines += lineCount;
    totalChars += charCount;
  }

  if (args.length > 2)
  {
    writefln("-------------------------------------\n%8s%8s%8s total",
            totalLines, totalWords, totalChars);
  }

  writeln("-------------------------------------");
  foreach (word; dictionary.keys.sort)
  {
    writefln("%3s %s", dictionary[word], word);
  }
}