美文网首页Flutter
flutter Set集合妙用

flutter Set集合妙用

作者: HawkFlying | 来源:发表于2021-01-15 10:57 被阅读0次

    Set

    Set是不能重复的集合,所以可以用Set去重;

    基本数据Set去重

    String、int、double类型示例,如下:
    String类型:

    Set s=new Set();
    s.add('a');
    s.add('b');
    s.add('');
    s.add('c');
    s.add('a');
    s.add('b');
    
    print(s);   // {a, b,,c}
    print(s.toList()); // [a, b,,c]
    

    int类型:

    Set s=new Set();
    s.add(1);
    s.add(2);
    s.add(1);
    s.add(1);
    s.add(3);
    
    print(s);   // {1, 2,3}
    print(s.toList()); // [1, 2,3]
    

    double类型:

    Set s=new Set();
    s.add(1.2);
    s.add(1.2);
    s.add(1.3);
    
    print(s);   // {1.2, 1,3}
    print(s.toList()); // [1.2,1.3]
    

    可以看到,Set集合可直接对String、int、double类型去重
    Map、List、bool类型和String、int、double类型对比示例,如下:

        Set _s = Set();
        _s.add({'a': 1, 'b': 2});
        _s.add({'a': 1, 'b': 2});
        _s.add({'a': 1, 'b': 2, 'c': 3});
        _s.add([
          1,
          2,
        ]);
        _s.add([
          1,
          2,
        ]);
        _s.add([1, 2, 3]);
        _s.add(true);
        _s.add(false);
        _s.add(1);
        _s.add(1);
        _s.add(1.2);
        _s.add(1.2);
        _s.add('a');
        _s.add('a');
    
    效果.png
    通过上面对比示例可知,Set集合可直接对String、int、double类型去重,但对Map、List、bool类型去重失效

    自定义对象Set去重

    自定义对象Set去重失效
    
    TestModel model = TestModel('e', boolValue: false);
     Set _s = Set();
     _s.add(TestModel('a', boolValue: false));
     _s.add(TestModel('b',));
     _s.add(TestModel( 'c', ));
     _s.add(TestModel( 'd',));
     _s.add(TestModel('a', boolValue: true));
     _s.add(TestModel('a', boolValue: true));
     _s.add(model);
     _s.add(model);
     ...
    
    ///自定义对象
    class TestModel {
      String title;
      bool boolValue;
    
      TestModel(this.title, {this.boolValue = true});
      
      @override
      ///用于自定义对象内容展示 
      String toString() {
        return 'class $title  值为${boolValue ?? 'null'}\n';
      }
    
    效果.png

    可以看到,当自定义对象实例化为同一个对象时,Set会过滤掉同一个实例化的对象;当自定义对象实例化为不同对象时,Set不会去重,即使对象数据内容一样,这不符合我们的业务;

    让自定义对象Set去重有效
    试着重写自定义对象==方法:
    
    TestModel model = TestModel('e', boolValue: false);
     Set _s = Set();
     _s.add(TestModel('a', boolValue: false));
     _s.add(TestModel('b',));
     _s.add(TestModel( 'c', ));
     _s.add(TestModel( 'd',));
     _s.add(TestModel('a', boolValue: true));
     _s.add(TestModel('a', boolValue: true));
     _s.add(model);
     _s.add(model);
     ...
    
    ///自定义对象
    class TestModel {
      String title;
      bool boolValue;
    
      TestModel(this.title, {this.boolValue = true});
      
      @override
      ///用于自定义对象内容展示 
      String toString() {
        return 'class $title  值为${boolValue ?? 'null'}\n';
      }
     
      @override
      ///重写==方法
      bool operator ==(other) {
        if (null == other || other is! TestModel) {
          return false;
        }
        final TestModel otherModel = other;
        return (null != title &&
            title.length > 0 &&
            title.compareTo(otherModel?.title ?? '') == 0);
      }
    }
    
    效果.png

    可以看到,重写自定义对象==方法,Set还是不能去重;

    再试下重写自定义对象hashCode和==方法
    
    TestModel model = TestModel('e', boolValue: false);
     Set _s = Set();
     _s.add(TestModel('a', boolValue: false));
     _s.add(TestModel('b',));
     _s.add(TestModel( 'c', ));
     _s.add(TestModel( 'd',));
     _s.add(TestModel('a', boolValue: true));
     _s.add(TestModel('a', boolValue: true));
     _s.add(model);
     _s.add(model);
     ...
    
    ///自定义对象
    class TestModel {
      String title;
      bool boolValue;
    
      TestModel(this.title, {this.boolValue = true});
      
      @override
      ///用于自定义对象内容展示 
      String toString() {
        return 'class $title  值为${boolValue ?? 'null'}\n';
      }
     
        @override
      ///重写hashCode方法
      int get hashCode {
        int code = title?.hashCode ?? 0;
        return code;
      }
    
      @override
      ///重写==方法
      bool operator ==(other) {
        if (null == other || other is! TestModel) {
          return false;
        }
        final TestModel otherModel = other;
        return (null != title &&
            title.length > 0 &&
            title.compareTo(otherModel?.title ?? '') == 0);
      }
    }
    
    效果.png

    上面重写自定义对象hashCode和==方法,以title不同区分不同对象;
    可以看到,重写自定义对象hashCode和==方法,Set集合对自定义对象去重才有效;并且Set集合里有相同对象时(相同对象为上面自定义对象title值相同的对象),后面相同的对象就不会被加入Set集合里了( 如上面title一样,boolValue不一样,这样被认为相同的对象,因为重写自定义对象hashCode和==方法,以title不同区分不同对象;Set集合里最开始加入的TestModel('a', boolValue: false),数据不会被相同对象TestModel('a', boolValue: true)覆盖 )。

    Set去重

    • 对于String、int、double类型,Set集合可直接去重;对于List、Map、bool类型,Set集合去重失效;
    • 对于自定义对象,需要重写自定义对象hashCode和==方法,才可用Set集合去重;
    • 重写自定义对象hashCode和==方法,可根据自己的业务需求决定以什么数据内容来区分不同的对象;
    • 对于同一个实例化的对象,不管是基本数据对象还是自定义对象,Set集合都会去重,这种在flutter生命周期中有应用,如Form源码里;

    Set集合子元素的有序性

    网上介绍flutter Set集合时一般会介绍Set没有顺序,这点不太理解,可能是不能通过索引来获取对应的值吧,像Java语言的Set集合确实是无序的,但flutter的Set集合保持着子元素的有序性。 如下:

    Set s=new Set();
    s.add(1);
    s.add(2);
    s.add(1);
    s.add(1);
    s.add(3);
    
    print(s.toList()); // [1, 2,3]
    

    可以看到,将Set通过toList()方法转为List后,List里子元素的顺序和子元素插入Set集合的顺序是一致;对于自定义对象亦是如此,可自行验证。
    为什么Set集合会保持子元素插入顺序呢
    我们看下Set源码,如下:

    /*...
     * * A [HashSet] is unordered, which means that its iteration order is
     *   unspecified,
     * * [LinkedHashSet] iterates in the insertion order of its elements, and
     * * a sorted set like [SplayTreeSet] iterates the elements in sorted order.
     *...
     */
    abstract class Set<E> extends EfficientLengthIterable<E> {
      /**
       * Creates an empty [Set].
       *
       * The created [Set] is a plain [LinkedHashSet].
       * As such, it considers elements that are equal (using [operator ==]) to be
       * indistinguishable, and requires them to have a compatible
       * [Object.hashCode] implementation.
       *
       * The set is equivalent to one created by `new LinkedHashSet<E>()`.
       */
      factory Set() = LinkedHashSet<E>;
      ...
    

    从源码我们可知,Set()是一个工厂构造方法,根据工厂构造方法的特点,Set是由LinkedHashSet实例化的。

     A [HashSet] is unordered, which means that its iteration order is unspecified,
     [LinkedHashSet] iterates in the insertion order of its elements, and a sorted set like [SplayTreeSet] iterates the elements in sorted order.
    

    从上面注释可知,HashSet是无序的,LinkedHashSet保持着子元素插入的顺序。而Set是由LinkedHashSet实例化的,所以Set保持着子元素插入的顺序。
    如想要深入分析LinkedHashSet,LinkedHashSet源码中有很多external声明的方法,可参考如何找到flutter external声明方法的实现

    demo传送门

    相关文章

      网友评论

        本文标题:flutter Set集合妙用

        本文链接:https://www.haomeiwen.com/subject/iwmfaktx.html