web-dev-qa-db-ja.com

DartのさまざまなMap実装の違いは何ですか?

DartにはMapタイプがあり、 HashMapLinkedHashMapSplayTreeMap などの実装があります。これらの異なるマップ実装の違いは何ですか?

30
Seth Ladd

Dartには、List、Set、Mapなどのコレクションのサポートが組み込まれています。 Dartにはさまざまなマップの実装があります。実装間の長所と短所を理解すると、十分な情報に基づいた決定を下すのに役立ちます。

(注:これはDart M3の頃に書かれているため、以下の内容は現時点ではドキュメントと一致しない可能性があります。)

マップとは何ですか?

マップは連想コンテナであり、キーを値にマッピングします。キーは一意であり、1つの値のみを指すことができます。キーをnullにすることはできませんが、値をnullにすることはできます。

マップリテラル

Dartは次のように マップリテラル をサポートします:

_var accounts = {'323525': 'John Smith', '588982': 'Alice Jones'};
_

仕様では、マップリテラルは挿入順序を維持する必要があるとされています。これは、accountsLinkedHashMapのインスタンスであることを意味します。

仕様には、マップリテラルキーは文字列でなければならないことも記載されています。これは将来変更される可能性があります。

新しいMap()

Dartはファクトリコンストラクターをサポートしているため、次のようにMapの新しいインスタンスを作成できます。

_var accounts = new Map();
_

Mapクラスは抽象です。つまり、ファクトリコンストラクタは実際にはMapのサブクラスのインスタンスを作成します。では、accountsの実際のタイプは何ですか?

以前のバージョンのDartは、new Map()コンストラクターからHashMapの新しいインスタンスを作成しました。ただし、 Dart bug 58 は、_{}_と_new Map_が同じ型を返すようにするために、_new Map_はまもなくLinkedHashMapのインスタンスを返すと述べています。

LinkedHashMap(または、InsertionOrderedMap)

LinkedHashMapは、挿入されたのと同じ順序でキーと値を繰り返し処理します。

注:LinkedHashMapはおそらくInsertionOrderedMapに名前が変更されます。進行状況については ダートバグ2349 に従ってください。

次に例を示します。

_import 'Dart:collection';
main() {
  var ordered = new LinkedHashMap();
  ordered['32352'] = 'Alice';
  ordered['95594'] = 'Bob';

  for (var key in ordered.keys) {
    print(key);
  }

  // guaranteed to print 32352, then 95594
}
_

これが LinkedHashMapのソースコード です。 (このリンクが機能しなくなった場合は、クラスの名前が変更された可能性があります)

HashMap

HashMapは、挿入順序を維持する保証はありません。 HashMapのキーまたは値を反復処理する場合、特定の順序を期待することはできません。

HashMapは、 ハッシュテーブル を使用して実装されます。

新しいHashMapを作成する例を次に示します。

_import 'Dart:collection';
main() {
  var accounts = new HashMap();
}
_

挿入順序を維持する必要がない場合は、HashMapを使用してください。

これが HashMapのソースコード です。

SplayTreeMap

スプレーツリーは、最近アクセスした要素がすぐに再びアクセスできるという追加のプロパティを備えた、自己平衡型のバイナリ検索ツリーです。 O(log(n))償却時間内に、挿入、ルックアップ、削除などの基本的な操作を実行します。

_import 'Dart:collection';
main() {
  var accounts = new SplayTreeMap();
}
_

SplayTreeMapでは、すべてのキーが同じタイプである必要があります。

スプレーツリーは、キャッシュのように頻繁に保存およびアクセスされるデータに適しています。その理由は、ツリーの回転を使用して要素をルートに移動し、より頻繁にアクセスできるようにするためです。パフォーマンスは、ツリーの自己最適化によってもたらされます。つまり、頻繁にアクセスされる要素は、上部に移動します。ただし、ツリーがいたるところで同じように頻繁にアクセスされる場合は、スプレーツリーマップを使用する意味はほとんどありません。

例としては、ネットワークパケットを非常に高速で受信するモデムルーターがあります。モデムは、どのパケットがどのワイヤに入るのかを決定する必要があります。キーがIPで、値が宛先であるマップ実装を使用できます。ほとんどのIPアドレスは複数回使用されるため、これらはツリーのルートから見つけることができるため、このシナリオにはスプレーツリーマップが適しています。

41
Seth Ladd

別の方法があります。

マルチマップ

import 'package:quiver/collection.Dart';

algorithms() {
  var ordered = new ListMultimap();
  ordered.add('32352', 'Alice');
  ordered.add('95594', 'Bob');
  ordered.add('32352', 'Alice2');

  for (var key in ordered.keys) {
    print(key);
  }

  for (var value in ordered.values) {
    print(value);
  }

  // print in ascending order
  // flutter: 32352
  // flutter: 95594
  // flutter: Alice
  // flutter: Alice2
  // flutter: Bob
}
0
madeinQuant