How to use distinct to bring a single result of each Dart/Flutter item

Asked

Viewed 408 times

0

Hello, I am trying to bring a single result of each consuming title from an API. As this picture shows I’m having repeated titles inserir a descrição da imagem aqui

What way could I make it right, it follows code as far as I’ve tried with distinct

class AnimeBloc
    class AnimeBloc{

    final BehaviorSubject<List<Animes>> _listController   =BehaviorSubject<List<Animes>>.seeded([]);
    Sink<List<Animes>>  get listIn  => _listController.sink;
    Observable<List<Animes>> outList;

    Api api=  Api();


    AnimeBloc(){

      outList=_listController.stream.distinct().asyncMap((d)=>api.getAnimeName());
      print("teste $outList");
    }




    dispose(){
      _listController.close();
    }


    }

Here api class

      Dio dio = Dio();

     Future<List<Animes>> getAnimes()async{
       Response response    =await dio.get(requestAnimes);
       if(response.statusCode==200){
         List<Animes> animes=
         (response.data as List).map((item)=> Animes.fromJson(item)).toList();
         return animes;
       }else {
         Exception("Erro na requisição");
       }
     }

and my screen with StreamBuilder

    StreamBuilder(
                        stream: bloc.outList,

                        builder: (context, AsyncSnapshot<List<Animes>> snapshot){
                          if(!snapshot.hasData){return Center(child: CircularProgressIndicator(),);}
                          else if(snapshot.hasError){return Center(child: Text("Error "),);}
                          List<Animes> animes = snapshot.data;


                          return ListView.builder(
                              itemCount: animes.length,
                              itemBuilder:(context, index){
                                return
                                  GestureDetector(
                                    child: AnimeMainTile(
                                        snapshot.data[index]
                                    ),
                                    onTap: (){
                                     print( snapshot.data[index]);
                                    },
                                  );
                              }

                          );
                        },
                      ),
                    ),

2 answers

0

You get exactly what you’re looking for if you use one Set instead of a List.

The Set does not let you have duplicated objects, a List cue; To List is an ordered list of objects, already the Set does not guarantee that you maintain the same order;

Just use the method .toSet() from a List (or .toList() if you have a Set)

Or you filter your own List.

  • 1

    I don’t remember if the Set maintains the insertion order (which could be something important in displaying this app, it wasn’t clear to me), but I don’t think

  • Ah, you also need to implement equals and the hashCode in class Anime to ensure the functioning of Set

  • Exactly, it is necessary to implement Equal and hash, it is based on a hash that sets store objects. O Set does not guarantee you order, it means that if the order is the same great otherwise then you will have to order.

0


As mentioned in the other responses, you can implement equals and hash in Dart, to use the Set() directly with the class Animes. This means that you can decide exactly how the program will judge whether two objects in this class are equal or not (e.g. all your fields need to be equal, or just some of them).

As you care about the order, you can use the Linkedhashset also. This is an implementation of the Set that maintains the insertion order.

However, another solution would be to filter the list with a for, using only one field as identifier, and add into one Set only for verification of existence:

We have the original list:

 List<Animes> animes = snapshot.data;

And we created a second list that we will popular with the distinct items. In addition to this list, we created a set to verify the existence:

List<Animes> animesFiltrados = [];
Set<String> animesInclusos = Set();

So, we went through the items on the original list, making sure they’re already included no Set. If an item is not, we include both the new list and the set. If it is, we do nothing:

for (Animes anime in animes){
    if (!animesInclusos.contains(anime.nome)){
        animesInclusos.add(anime.nome)
        animesFiltrados.add(anime)
    }
}

You did not include your class in the question, but I assume that it has a string field of the Name type, for example.

Don’t forget to base yourself on the new generated list when drawing the screen:

return ListView.builder(
                              itemCount: animesFiltrados.length,
                              itemBuilder:(context, index){
                                return
                                  GestureDetector(
                                    child: AnimeMainTile(
                                        animesFiltrados[index]
                                    ),
                                    onTap: (){
                                     print(animesFiltrados[index]);
                                    },
                                  );
                              }

                          );

Keep in mind that my suggestion only works if there are two different items but with the same value in the "Name" field (for example, an old movie and the remake has the same name, with different release dates). In this case you would need to use another field combination or implement Equals and Hash.

It is also worth remembering that this solution goes through the entire list, which can cause problems if you bring this information paginated or if the list is too large.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.