【问题标题】:How can I compare Lists for equality in Dart?如何比较 Dart 中的列表是否相等?
【发布时间】:2012-05-11 09:10:39
【问题描述】:

我正在像这样比较 Dart 中的两个列表:

main() {
    if ([1,2,3] == [1,2,3]) {
        print("Equal");
    } else {
        print("Not equal");
    }   
}

但他们从来都不是平等的。 Dart API 中似乎没有用于比较列表或集合的 equal() 方法。有没有合适的方法来做到这一点?

【问题讨论】:

    标签: dart


    【解决方案1】:

    最方便的选择是在List 类上创建extension method

    extension on List {
      bool equals(List list) {
        if(this.length!=list.length) return false;
        return this.every((item) => list.contains(item));
      }
    }
    

    上述代码的作用是检查第一个列表 (this) 中的每个 item 是否包含在第二个列表 (list) 中。但是,这仅适用于两个列表长度相同的情况。 当然,您可以替换为其他解决方案之一或修改此解决方案,我只是为了方便起见。无论如何,要使用此扩展程序,请执行以下操作:

    List list1, list2
    list1.equals(list2);
    

    【讨论】:

    • 你的扩展方法不对。 [1, 2, 2, 3].equals([1, 3, 3, 2]) 返回true
    【解决方案2】:
    bool areListsEqual(var list1, var list2) {
        // check if both are lists
        if(!(list1 is List && list2 is List)
            // check if both have same length
            || list1.length!=list2.length) {
            return false;
        }
         
        // check if elements are equal
        for(int i=0;i<list1.length;i++) {
            if(list1[i]!=list2[i]) {
                return false;
            }
        }
         
        return true;
    }
    

    【讨论】:

      【解决方案3】:

      在 Dart 中比较两个 int 列表是否相等的简单解决方案是使用 Sets(不检查列表中元素的顺序):

      void main() {
        var a = [1,2,3];
        var b = [1,3,2];
        
        var condition1 = a.toSet().difference(b.toSet()).isEmpty;
        var condition2 = a.length == b.length;
        var isEqual = condition1 && condition2;
        isEqual ? print(true) : print(false); // Will print true
      }
      

      【讨论】:

        【解决方案4】:

        对于使用 Flutter 的用户,它具有原生函数 listEquals,用于比较深度相等。

        import 'package:flutter/foundation.dart';
        
        var list1 = <int>[1, 2, 3];
        var list2 = <int>[1, 2, 3];
        
        assert(listEquals(list1, list2) == true);
        
        import 'package:flutter/foundation.dart';
        
        var list1 = <int>[1, 2, 3];
        var list2 = <int>[3, 2, 1];
        
        assert(listEquals(list1, list2) == false);
        

        请注意,according to the documentation:

        上面的术语“深”指的是第一级相等:如果元素是映射、列表、集合或其他集合/复合对象,那么这些元素的值不会逐个元素进行比较,除非它们的相等运算符(Object.operator==) 这样做。

        因此,如果您正在寻找无限级别的平等,请查看DeepCollectionEquality,正如Patrice Chalin 所建议的那样。

        此外,如果您需要针对不同收藏的此类功能,还有setEqualsmapEquals

        【讨论】:

          【解决方案5】:

          这样的东西对你有用吗?

          try {
            Expect.listEquals(list1, list2);
          } catch (var e) {
            print("lists aren't equal: $e");
          }
          

          例子:

          main() {
            List<int> list1 = [1, 2, 3, 4, 5];
            List<int> list2 = new List.from(list1);
            try {
              Expect.listEquals(list1, list2);
            } catch (var e) {
              print("lists aren't equal: $e");
            }
            list1.removeLast();
            try {
              Expect.listEquals(list1, list2);
            } catch (var e) {
              print("Lists aren't equal: $e");
            }
          }
          

          第二次尝试打印:

          Lists aren't equal: Expect.listEquals(list length, expected: <4>, actual: <5>) fails
          

          【讨论】:

          • 这个 Equal 类是否在 API 中定义?如果是,我无法追踪它。似乎这些类公开一个运算符或方法来比较与 Dart 的相等性然后与 == 运算符一起使用是最有意义的。
          • 同意。它实际上是 dart:core 中的 Expect 类。奇怪的是,除非我误读了,否则 Expect.listEquals 下的 cmets 声明这与列表实现使用的标准相等性检查不同,正如您和 Lars 指出的那样,它似乎实际上并不存在。跨度>
          【解决方案6】:

          在 Dart 中比较两个 int 列表的相等性 的简单解决方案是使用 join() 将其作为字符串进行比较:

          var a = [1,2,3,0];
          var b = [1,2,3,4];
          
          a.join('') == b.join('') ? return true: return false;
          

          【讨论】:

          • 这不可靠。考虑 [12, 3] 和 [1, 23]
          • 谢谢,你说得对,它在你的具体例子中不起作用。
          • 它可以使用排序和空格作为分隔符。但是计算时间可能超过 O(n2)。
          【解决方案7】:

          有时想要比较的不是列表本身,而是包含列表的一些对象(类实例)

          让你有一个带有列表字段的类,比如

          class A {
            final String name;
            final List<int> list;
          
            A(this.name, this.list);
          }
          

          想要比较它的实例,可以使用equatable package

          class A extends Equatable {
            final String name;
            final List<int> list;
            
            A(this.name, this.list);
            
            @override
            List<Object> get props => [name, list];
          }
          

          然后使用==简单地比较对象

          final x = A('foo', [1,2,3]);
          final y = A('foo', [1,2,3]);
          print(x == y); // true
          

          【讨论】:

          • 我不认为 Equatable 提供了可以像在示例中那样使用的构造函数,并且无论您是否需要提供 props getter 的实现。 IE。构造函数就像A(this.name, this.list); 和一个@override 注释List&lt;Object&gt; get props =&gt; [name, list];。自从您写下答案后,也许图书馆发生了变化。
          • 我浏览了 Equatable 存储库,0.6.x 的版本需要我提到的更改。
          【解决方案8】:

          要完成 Gunter 的回答:比较列表是否相等(而不是身份)的推荐方法是使用以下包中的 Equality 类

          import 'package:collection/collection.dart';
          

          编辑:在 1.13 之前,是 import 'package:collection/equality.dart';

          例如:

          Function eq = const ListEquality().equals;
          print(eq([1,'two',3], [1,'two',3])); // => true
          

          上面打印true,因为对应的列表元素是identical()。如果您想(深入)比较可能包含其他集合的列表,请改用:

          Function deepEq = const DeepCollectionEquality().equals;
          List list1 = [1, ['a',[]], 3];
          List list2 = [1, ['a',[]], 3];
          print(    eq(list1, list2)); // => false
          print(deepEq(list1, list2)); // => true
          

          还有其他 Equality 类可以通过多种方式组合,包括 Maps 的相等性。您甚至可以对集合进行无序(深度)比较:

          Function unOrdDeepEq = const DeepCollectionEquality.unordered().equals;
          List list3 = [3, [[],'a'], 1];
          print(unOrdDeepEq(list2, list3)); // => true
          

          详情请参阅package API documentation。像往常一样,要使用这样的包,您必须在pubspec.yaml 中列出它:

          dependencies:
            collection: any
          

          【讨论】:

          • 感谢 DeepCollectionEquality 参考。它为我的 peons 清除了一些信息。
          • 这是一个很棒的包。感觉它应该是一个内置的库。感谢您的回答。
          • 谢谢!它帮助了我
          【解决方案9】:

          Built Collections 库为 Dart 提供了不可变的集合,包括相等、散列和其他好东西。

          如果您正在做一些需要平等的事情,那么您也有可能在不变性方面做得更好。

          http://www.dartdocs.org/documentation/built_collection/0.3.1/index.html#built_collection/built_collection

          【讨论】:

            【解决方案10】:

            Dart 中的集合没有内在的平等。两个集合不相等,即使它们包含与元素完全相同的对象。

            collection library 提供了定义这种相等性的方法。在这种情况下,对于 例子

            IterableEquality().equals([1,2,3],[1,2,3])
            

            是一个相等性,如果两个列表包含相同的元素,则认为它们完全相等。

            【讨论】:

            • 请在下面查看更多答案,现在有办法做到这一点。
            【解决方案11】:

            我偶然发现了这个

            import 'package:collection/equality.dart';
            
            void main(List<String> args) {
              if (const IterableEquality().equals([1,2,3],[1,2,3])) {
              // if (const SetEquality().equals([1,2,3].toSet(),[1,2,3].toSet())) {
                  print("Equal");
              } else {
                  print("Not equal");
              }
            }
            

            更多信息https://github.com/dart-lang/bleeding_edge/tree/master/dart/pkg/collection

            【讨论】:

              【解决方案12】:

              在一切正常之前,你可以使用这个:

                /**
                 * Returns true if the two given lists are equal.
                 */
                bool _listsAreEqual(List one, List two) {
                  var i = -1;
                  return one.every((element) {
                    i++;
              
                    return two[i] == element;
                  });
                }
              

              【讨论】:

              • 如果第一个列表更大会崩溃
              • 并为 [3, 5] 和 [3, 5, 7, 9] 返回 true
              【解决方案13】:

              虽然这个问题已经相当老了,但该功能还没有在 Dart 中原生实现。我需要深度相等比较 (List&lt;List&gt;),所以我现在通过递归调用从上面借用:

              bool _listsAreEqual(list1, list2) {
               var i=-1;
               return list1.every((val) {
                 i++;
                 if(val is List && list2[i] is List) return _listsAreEqual(val,list2[i]);
                 else return list2[i] == val;
               });
              }
              

              注意:混合集合类型(即List&lt;Map&gt;)时,这仍然会失败 - 它只涵盖List&lt;List&lt;List&gt;&gt; 等等。

              关于这方面的最新飞镖问题似乎是https://code.google.com/p/dart/issues/detail?id=2217(最后更新于 2013 年 5 月)。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2013-03-29
                • 2013-10-09
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-12-10
                • 1970-01-01
                • 2016-03-06
                相关资源
                最近更新 更多