如何在Dart中比较列表的相等性?

180

我正在使用Dart比较两个列表,代码如下:

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

但它们永远不相等。在Dart API中似乎没有equal()方法来比较列表或集合。是否有适当的方法来做到这一点?

15个回答

269
为了完善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

还有其他可以以许多方式组合的平等类别,包括Map的相等性。你甚至可以对集合执行无序(深度)比较:

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

有关详细信息,请参见软件包API文档。像往常一样,要使用这样的软件包,您必须在pubspec.yaml中列出它:

dependencies:
  collection: any

4
似乎无法处理对象列表,我有一个对象列表,即使它们匹配,我也会得到false。使用 eqdeepEq 都是如此。 - Jeremy
1
对于复杂对象比较,请确保实现Equatable以使其在DeepCollectionEquality上工作。 - Anupdas

200

对于使用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);

请注意,根据文档所述:

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

因此,如果您正在寻找无限级别的相等性,请查看DeepCollectionEquality,如Patrice Chalin所建议的那样。
此外,如果您需要不同集合的此类功能,则有setEqualsmapEquals

23

Dart中的集合没有固有的相等性。即使两个集合包含完全相同的对象作为元素,它们也不相等。

collection库提供了定义这种相等性的方法。例如,在这种情况下:

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

如果两个列表包含完全相同的元素,那么这个等式就会认为它们完全相等。


10

这些是为Flutter设计的,纯Dart环境下无法使用。对于Dart,你可以使用collection包。 - undefined

9

6
在Dart中比较两个整数列表的简单方法是使用Set(不考虑列表中元素的顺序):
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;
  print(isEqual); // Will print true
}

5

虽然这个问题已经比较老了,但是在Dart中这个功能仍然没有被原生支持。我需要进行深度相等比较(List<List>),所以我从上面借鉴了方法并进行了递归调用:

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<Map>)时,仍然会失败 - 它只涵盖List<List<List>>等内容。
最新的Dart问题似乎是https://code.google.com/p/dart/issues/detail?id=2217(最后更新于2013年5月)。

3

3
有时候我们想要比较的不仅是列表本身,还有一些包含列表的对象(类实例)。
例如,如果你有一个带有列表字段的类,像这样:
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的实现。也就是说,构造函数只需写成A(this.name, this.list);,并添加一个带有@override注解的List<Object> get props => [name, list];方法。也许自你回答以来库已经发生了变化。 - swalog
我查看了Equatable存储库,版本为0.6.x的需要进行我提到的更改。 - swalog

2
最方便的选择是在List类上创建一个扩展方法。 扩展方法
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);

11
你的扩展方法有误。[1,2,2,3].equals([1,3,3,2]) 返回 true - nipunasudha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接