【问题标题】:What are the differences between the different Map implementations in Dart?Dart 中不同的 Map 实现有什么区别?
【发布时间】:2013-02-02 13:37:33
【问题描述】:

Dart 有一个 Map 类型,具有 HashMapLinkedHashMapSplayTreeMap 等实现。这些不同的 Map 实现有什么区别?

【问题讨论】:

    标签: dart


    【解决方案1】:

    Dart 内置了对 List、Set 和 Map 等集合的支持。 Dart 有不同的 Map 实现。了解实现之间的优缺点可以帮助您做出明智的决定。

    (注意:这是在 Dart M3 的时候写的,所以下面的内容可能与此刻的文档不匹配。)

    什么是地图?

    Map 是一个关联容器,将键映射到值。键是唯一的,并且可以指向一个且只有一个值。键不能为空,但值可以为空。

    地图文字

    Dart 支持Map literals,像这样:

    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 5803 声明为了使{}new Map 返回相同的类型,new Map 将很快返回LinkedHashMap 的实例。

    LinkedHashMap(或,InsertionOrderedMap)

    LinkedHashMap 以插入的相同顺序遍历键和值。

    注意: LinkedHashMap 可能会被重命名为 InsertionOrderedMap。关注Dart bug 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
    }
    

    这里是source code for LinkedHashMap。 (如果此链接停止工作,可能是因为该类已重命名)

    哈希映射

    HashMap 不能保证保持插入顺序。当您遍历 HashMap 的键或值时,您不能期望一定的顺序。

    HashMap 是使用hash table 实现的。

    这里是一个创建新HashMap的例子:

    import 'dart:collection';
    main() {
      var accounts = new HashMap();
    }
    

    如果您不关心维护插入顺序,请使用 HashMap。

    这里是source code of HashMap

    SplayTreeMap

    splay 树是一种自平衡二叉搜索树,具有最近访问的元素可以快速再次访问的附加属性。它在 O(log(n)) 摊销时间内执行插入、查找和删除等基本操作。

    import 'dart:collection';
    main() {
      var accounts = new SplayTreeMap();
    }
    

    SplayTreeMap 要求所有键的类型相同。

    对于经常存储和访问的数据(如缓存),展开树是一个不错的选择。原因是他们使用树旋转来将元素带到根,以便更频繁地访问。性能来自树的自我优化。也就是说,经常访问的元素被移到更靠近顶部的位置。但是,如果树的访问频率相同,那么使用张开树图就没有什么意义了。

    一个示例是调制解调器路由器以非常高的速率接收网络数据包。调制解调器必须决定哪个数据包进入哪条线路。它可以使用映射实现,其中键是 IP,值是目的地。在这种情况下,张开树图是一个不错的选择,因为大多数 IP 地址会被多次使用,因此可以从树的根部找到这些地址。

    【讨论】:

    • 向展开树添加更多内容:他们使用tree rotations 将一个元素带到顶部,以便更频繁地访问。性能来自树的自我优化。也就是说,频繁访问的元素被移到更靠近顶部的位置,以便更频繁地访问。这就是为什么它是缓存之类的好选择。但是,如果树的访问频率相同,那么使用张开树图就没有什么意义了。
    • 凯,感谢您的额外澄清。随时更新答案:)
    • 当然,加上一个例子。
    【解决方案2】:

    还有一个选择。

    多地图

    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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-16
      • 1970-01-01
      • 1970-01-01
      • 2016-12-24
      • 2023-03-04
      相关资源
      最近更新 更多