178

I'm comparing two lists in Dart like this:

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

But they are never equal. There doesn't seem to be an equal() method in the Dart API to compare Lists or Collections. Is there a proper way to do this?

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Mark B
  • 2,870
  • 3
  • 20
  • 18

15 Answers15

262

To complete Gunter's answer: the recommended way to compare lists for equality (rather than identity) is by using the Equality classes from the following package

import 'package:collection/collection.dart';

Edit: prior to 1.13, it was import 'package:collection/equality.dart';

E.g.:

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

The above prints true because the corresponding list elements that are identical(). If you want to (deeply) compare lists that might contain other collections then instead use:

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

There are other Equality classes that can be combined in many ways, including equality for Maps. You can even perform an unordered (deep) comparison of collections:

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

For details see the package API documentation. As usual, to use such a package you must list it in your pubspec.yaml:

dependencies:
  collection: any
creativecreatorormaybenot
  • 114,516
  • 58
  • 291
  • 402
Patrice Chalin
  • 15,440
  • 7
  • 33
  • 44
  • 4
    Doesn't seem to work with lists of objects. I have a list of objects and even when they match, I get `false`. Both with `eq` and `deepEq`. – Jeremy Jan 27 '22 at 17:13
  • 1
    For complex object comparison, ensure to implement `Equatable` for this to work on `DeepCollectionEquality` – Anupdas Jan 07 '23 at 07:07
192

For those using Flutter, it has the native function listEquals, which compares for deep equality.

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);

Note that, according to the documentation:

The term "deep" above refers to the first level of equality: if the elements are maps, lists, sets, or other collections/composite objects, then the values of those elements are not compared element by element unless their equality operators (Object.operator==) do so.

Therefore, if you're looking for limitless-level equality, check out DeepCollectionEquality, as suggested by Patrice Chalin.

Also, there's setEquals and mapEquals if you need such feature for different collections.

Hugo Passos
  • 7,719
  • 2
  • 35
  • 52
22

Collections in Dart have no inherent equality. Two sets are not equal, even if they contain exactly the same objects as elements.

The collection library provides methods to define such an equality. In this case, for example

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

is an equality that considers two lists equal exactly if they contain identical elements.

Lars Tackmann
  • 20,275
  • 13
  • 66
  • 83
9

I just stumbled upon this

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");
  }
}

more info https://github.com/dart-lang/bleeding_edge/tree/master/dart/pkg/collection

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
9

You can use the built-in listEquals, setEquals, and mapEquals function to check for equality now.

Here's the link to the docs: https://api.flutter.dev/flutter/foundation/listEquals.html

Ariz Armeidi
  • 91
  • 2
  • 3
5

While this question is rather old, the feature still hasn't landed natively in Dart. I had a need for deep equality comparison (List<List>), so I borrowed from above now with recursive call:

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;
 });
}

Note: this will still fail when mixing Collection types (ie List<Map>) - it just covers List<List<List>> and so-on.

Latest dart issue on this seems to be https://code.google.com/p/dart/issues/detail?id=2217 (last updated May 2013).

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
RealBlueSky
  • 446
  • 5
  • 8
5

A simple solution to compare the equality of two list of int in Dart can be to use Sets (without checking the order of the element in the list) :

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
}
LacticWhale
  • 209
  • 1
  • 11
Adrien Arcuri
  • 1,962
  • 1
  • 16
  • 30
3

The Built Collections library offers immutable collections for Dart that include equality, hashing, and other goodies.

If you're doing something that requires equality there's a chance you'd be better off with immutability, too.

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

3

Sometimes one want to compare not the lists themselves but some objects (class instances) that contain list(s)

Let you have a class with list field, like

class A {
  final String name;
  final List<int> list;

  A(this.name, this.list);
}

and want to compare its instances, you can use 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];
}

and then simply compare objects using ==

final x = A('foo', [1,2,3]);
final y = A('foo', [1,2,3]);
print(x == y); // true
Pavel
  • 5,374
  • 4
  • 30
  • 55
  • I don't think Equatable provides a constructor you can use as you do in your example, and regardless you are required to provide an implementation of a `props` getter. I.e. the constructor as just `A(this.name, this.list);` and an `@override` annotated `List get props => [name, list];`. Maybe the library changed since you wrote your answer. – swalog Aug 20 '20 at 08:55
  • I went through the Equatable repository, and versions as of `0.6.x` require the changes I mentioned. – swalog Aug 20 '20 at 09:14
2

The most convenient option would be to create an extension method on the List class.

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

What the above code does is that it checks to see if every single item from the first list (this) is contained in the second list (list). This only works, however, if both lists are of the same length. You can, of course, substitute in one of the other solutions or modify this solution, I am just showing this for the sake of convenience. Anyway, to use this extension, do this:

List list1, list2
list1.equals(list2);
Ardent Coder
  • 3,777
  • 9
  • 27
  • 53
eEeEeE
  • 63
  • 1
1

Would something like this work for you?

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

Example:

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");
  }
}

Second try prints:

Lists aren't equal: Expect.listEquals(list length, expected: <4>, actual: <5>) fails
Csaba Toth
  • 10,021
  • 5
  • 75
  • 121
scribeGriff
  • 637
  • 4
  • 8
  • Is this Equal class defined in the API? I couldn't track it down if it is. It would seem that it would make the most sense for these classes to expose an operator or method for comparing equality with Dart would then use with the == operator. – Mark B May 13 '12 at 14:14
  • Agreed. It's actually the Expect class in dart:core. Oddly, unless I'm misreading it, the comments under Expect.listEquals states that this is different than the standard check for equality used by the list implementation, which as you and Lars pointed out, doesn't seem to actually exist. – scribeGriff May 13 '12 at 17:50
1

Before things work, you can use this:

  /**
   * 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;
    });
  }
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
Tower
  • 98,741
  • 129
  • 357
  • 507
1
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;
}
Ahmed Raafat
  • 162
  • 4
  • 6
0

A simple solution to compare the equality of two list of int in Dart can be to compare it as String using join() :

var a = [1,2,3,0];
var b = [1,2,3,4];

a.join('') == b.join('') ? return true: return false;
Adrien Arcuri
  • 1,962
  • 1
  • 16
  • 30
0

There are lots of real answers given and one of the best answers is also accepted.

Here I made a method which takes two lists {no matter what type(int,double,String) of list} and gives the bool return.

Full Code with example

void main() {
  List x = [1, 2, 3];
  List y = [2, 3, 1];
  bool success = isTwoListAreSame(x, y);
  print('=> $success'); // true

  List x2 = ["A", "B", "C"];
  List y2 = ["P", "Q", "R"];

  bool success2 = isTwoListAreSame(x2, y2);
  print('=> $success2'); // false

  List x3 = ["A", "B", "C"];
  List y3 = ["A", "B"];

  bool success3 = isTwoListAreSame(x3, y3);
  print('=> $success3'); // false
}

Method

/// this method made for only same length of list
/// no matter elements of list are in order or not.
bool isTwoListAreSame(List list1, List list2) {
  // if both list are empty
  // then no need no compare
  // return true directly
  if (list1.isEmpty && list2.isEmpty) {
    return true;
  } else if (list1.length == list2.length) {
    // if both list have equal length
    // take first list every element and compare with second list every element
    // if all element are same it will return true
    final bool isSame = list1.every(
      (e1) {
        return list2.any(
          (e2) {
            return e1 == e2;
          },
        );
      },
    );

    return isSame;
  } else {
    // when both list are not equal length
    return false;
  }
}