2

I have a futurebuilder that builds the UI based on a List, it does the job, however I get duplicates due to the UI being built again and again whenever I navigate. My question is, is there a innate method in Dart that can remove duplicates from a list? I've tried this StackOverflow question however it doesn't work.

Here is my custom model:

class HomeList {
  Widget navigateScreen;
  String imagePath;
  PatientInfo patientInfo;

  HomeList({
    this.navigateScreen,
    this.imagePath = '',
    this.patientInfo,
  });

  static List<HomeList> homeList = [];
}

Here is my function for the futureBuilder i'm getting the data from my cloud_firestore:

  _getPatients() async {
    if (didLoadpatients == 0) {
      print('this is didloadpatients at start of func $didLoadpatients');
      var document = await db
          .collection('users')
          .document(mUser.uid)
          .collection('patients');

      document.getDocuments().then((QuerySnapshot query) async {
        query.documents.forEach((f) {
          uids.add(f.data['uID']);
        });
        didLoadpatients++;
      print('this is didloadpatients at end of func $didLoadpatients');
        for (var i = 0; i < uids.length; i++) {
          var userDocuments = await db.collection('users').document(uids[i]);
          userDocuments.get().then((DocumentSnapshot doc) {
            print(doc.data);
            homeList.add(HomeList(
                imagePath: 'assets/fitness_app/fitness_app.png',
                patientInfo: new PatientInfo.fromFbase(doc.data)));
          });
          print(homeList);
        }
      });
    } else 
    print('I am leaving the get patient function');
  }

  Future<bool> getData() async {
    _getCurrentUser();
    await Future.delayed(const Duration(milliseconds: 1500), () async {
      _getPatients();
    });
    return true;
  }

Any help would be appreciated thank you!

  • What elements does the list contain? – mezoni Nov 19 '19 at 06:11
  • the List contains 1. a path to an image asset, 2. another custom model that contains a users information, and lastly a Widget wherein if a user presses the Image.asset he/she will be navigated to that screen – Allen Andre Indefenzo Nov 19 '19 at 06:17

6 Answers6

6

To remove duplicates you can use Set Data Structure instead of List.

Just use Set instead of List to get unique values only.

Jay Mungara
  • 6,663
  • 2
  • 27
  • 49
  • Did I implement it wrong? It still gets duplicates whenever I load my screen that has the FutureBuilder.. I changed the `static List =[];` to static set myVariable = new LinkedHashSet(); and all other datatypes in the code from List to Set, but it still contains duplicates... https://imgur.com/a/LRg7Q8p – Allen Andre Indefenzo Nov 19 '19 at 06:16
  • Try Set homeList={}; A set can never contain any duplicate values. Please print the logs after you add values to the set homeList again by printing it. – Jay Mungara Nov 19 '19 at 07:12
4

Before Adding you can Remove Element from model this will Work

    dummymodel.removeWhere((m) => m.id == id);
    dummymodel.add(dummymodel.fromJson(data));
3

To Remove Duplicates from Data Model simply use Set (Data structure),

Original List with Duplicate Entries:

List<MyDataModel> mList = [MyDataModel(1), MyDataModel(2), MyDataModel(1), MyDataModel(3)];

New List that removes duplicate Entries from your List<MyDataModel>:

List<MyDataModel> mNewList = list.toSet().toList();

Output: The result will be like

MyDataModel(1), MyDataModel(2), MyDataModel(3)

Gowtham Subramaniam
  • 3,358
  • 2
  • 19
  • 31
2

To remove the duplicate elements from custom object list, you need to override == and hashcode methods in your POJO class and then add the items in Set and again convert set to list to remove duplicate objects. Below is the working code:-

class TrackPointList {
double latitude;
double longitude;
String eventName;
Time timeZone;

TrackPointList({
this.latitude,
this.longitude,
this.eventName,
this.timeZone,

});

@override
bool operator==(other) {
// Dart ensures that operator== isn't called with null
// if(other == null) {
//   return false;
// }
if(other is! TrackPointList) {
  return false;
}
// ignore: test_types_in_equals
return eventName == (other as TrackPointList).eventName;

}

int _hashCode;
@override
int get hashCode {
if(_hashCode == null) {
  _hashCode = eventName.hashCode;
}
return _hashCode;

}

factory TrackPointList.fromJson(Map<String, dynamic> json) => TrackPointList(
latitude: json["latitude"].toDouble(),
longitude: json["longitude"].toDouble(),
eventName: json["eventName"],
timeZone: timeValues.map[json["timeZone"]],

);

Map<String, dynamic> toJson() => {
"latitude": latitude,
"longitude": longitude,
"eventName": eventName,
"timeZone": timeValues.reverse[timeZone],

}; }

Above is the POJO class. Now below is the method which helps you to filter the objects according to the eventName data member.

List<TrackPointList> getFilteredList(List<TrackPointList> list){

final existing = Set<TrackPointList>();
final unique = list
    .where((trackingPoint) => existing.add(trackingPoint))
    .toList();

return unique;

}

This will work definitely. Please +1 if it helps you.

Deepak Sharma
  • 4,999
  • 5
  • 51
  • 61
1

I've come up with quite a brute force solution. Instead of

_getPatients() async {
    if (didLoadpatients == 0) {
      print('this is didloadpatients at start of func $didLoadpatients');
      var document = await db
          .collection('users')
          .document(mUser.uid)
          .collection('patients');

      document.getDocuments().then((QuerySnapshot query) async {
        query.documents.forEach((f) {
          uids.add(f.data['uID']);
        });
        didLoadpatients++;
      print('this is didloadpatients at end of func $didLoadpatients');
        for (var i = 0; i < uids.length; i++) {
          var userDocuments = await db.collection('users').document(uids[i]);
          userDocuments.get().then((DocumentSnapshot doc) {
            print(doc.data);
            homeList.add(HomeList(
                imagePath: 'assets/fitness_app/fitness_app.png',
                patientInfo: new PatientInfo.fromFbase(doc.data)));
          });
          print(homeList);
        }
      });
    } else 
    print('I am leaving the get patient function');
  }

I've done what @Jay Mungara says and clear my Set everytime my UI rebuilds:

_getPatients() async {
homeList.clear();
    if (didLoadpatients == 0) {
      print('this is didloadpatients at start of func $didLoadpatients');
      var document = await db
          .collection('users')
          .document(mUser.uid)
          .collection('patients');

      document.getDocuments().then((QuerySnapshot query) async {
        query.documents.forEach((f) {
          uids.add(f.data['uID']);
        });
        didLoadpatients++;
      print('this is didloadpatients at end of func $didLoadpatients');
        for (var i = 0; i < uids.length; i++) {
          var userDocuments = await db.collection('users').document(uids[i]);
          userDocuments.get().then((DocumentSnapshot doc) {
            print(doc.data);
            homeList.add(HomeList(
                imagePath: 'assets/fitness_app/fitness_app.png',
                patientInfo: new PatientInfo.fromFbase(doc.data)));
          });
          print(homeList);
        }
      });
    } else 
    print('I am leaving the get patient function');
  }

Thank you for all your answers!

0

this is a small examples to remove duplicate element

removeDuplicate() {
  List<dynamic> demoList = [
    {"userId": 1, "id": 1, "name": "thappu1"},
    {"userId": 2, "id": 2, "name": "appu"},
    {"userId": 1, "id": 1, "name": "thappu1"},
    {"userId": 2, "id": 2, "name": "appu"},
    {"userId": 2, "id": 2, "name": "appu"},
    {"userId": 2, "id": 2, "name": "appu"},
    {"userId": 2, "id": 2, "name": "appu"},
  ];
  var toRemove = {};
  demoList.forEach((e) {
    toRemove.putIfAbsent("$e", () => e);
  });
  print(toRemove.keys.toList());
}

output is

[{userId: 1, id: 1, name: thappu1}, {userId: 2, id: 2, name: appu}]

Jinto Joseph
  • 947
  • 6
  • 23