Home > database >  Unable to filter out an element of a List for my Flutter App
Unable to filter out an element of a List for my Flutter App

Time:07-30

I am learning FLutter and trying out stateful widgets such as sliders, lists, radio buttons and check boxes. I am trying to display a list of girls based on the following parameters:

  • Distance
  • Age
  • Status
  • Looking for

When the list is sorted by distance and I click on Is Serious, one of the girls: Monica, appears, when in fact she shouldn't as her looking for is casual.

enter image description here

Similarly, when the list is sorted by age and I click on Is Single, one of the girls: Reshmita appears, when in fact she shouldn't as her status is married.

enter image description here

The following is my code:

girls.dart

class Girls {
  String name;
  int distance;
  int age;
  String status;
  String lookingFor;

  Girls(this.name, this.distance, this.age, this.status, this.lookingFor);
}

girls.screen.dart

import 'package:flutter/material.dart';
import 'package:switch_circle_color/model/girls.dart';
import 'package:switch_circle_color/screens/gender.dart';
import 'package:switch_circle_color/screens/selected_girl_details.dart';

class GirlsScreen extends StatefulWidget {
  GirlsScreen({Key? key}) : super(key: key);

  @override
  State<GirlsScreen> createState() => _GirlsScreenState();
}

class _GirlsScreenState extends State<GirlsScreen> {
  int distance = 15;
  int age = 25;
  String sortCriterion = "distance";
  bool isSingle = false;
  bool isSerious = false;

  void changeDistance(double num) {
    setState(() {
      distance = num.round();

      populateFilteredGirls(distance, age);
      //this.filteredGirls = filteredGirls;
    });
  }

  void changeAgeLimit(double a) {
    setState(() {
      age = a.round();
      populateFilteredGirls(distance, age);
    });
  }

  List<Girls> allGirls = [
    Girls("Reshmita", 25, 33, "Married", "Serious"),
    Girls("Ankita", 17, 26, "Single", "Serious"),
    Girls("Rupali", 42, 28, "Single", "Casual"),
    Girls("Monica", 50, 24, "Single", "Casual"),
    Girls("Sakshi", 9, 27, "Married", "Casual"),
  ];

  List<Girls> filteredGirlsbyDistance = [];
  List<Girls> filteredGirlsbyAge = [];
  List<Girls> filteredGirls = [];
  //List<Girls> filteredGirlsbySerious = [];
  //List<Girls> filteredGirlsbySingle = [];

  String selectedGirlName = "";
  int? selectedGirlDistance;

  @override
  void initState() {
    super.initState();
    //filteredGirls = allGirls;
    distance = 20;
    age = 28;
    sortCriterion = "distance";
    isSingle = false;
    isSerious = false;

    (sortCriterion == "distance")
        ? allGirls.sort((a, b) => a.distance.compareTo(b.distance))
        : allGirls.sort((a, b) => a.age.compareTo(b.age));
    populateFilteredGirls(distance, age);
  }

  void populateFilteredGirls(int dis, int ag) {
    filteredGirlsbyDistance.clear();
    filteredGirlsbyAge.clear();
    filteredGirls.clear();
    //int len = filteredGirls.length;
    for (int i = 0; i < allGirls.length; i  ) {
      if (allGirls[i].distance <= dis) {
        filteredGirlsbyDistance.add(allGirls[i]);
      }
    }
    filteredGirls = filteredGirlsbyDistance;
    for (int i = 0; i < filteredGirls.length; i  ) {
      if (filteredGirls[i].age <= ag) {
        filteredGirlsbyAge.add(filteredGirls[i]);
      }
    }
    filteredGirls = filteredGirlsbyAge;
    //len = filteredGirls.length;
    if (isSingle == true) {
      for (int i = 0; i < filteredGirls.length; i  ) {
        if (filteredGirls[i].status.toLowerCase() != "single") {
          filteredGirls.remove(filteredGirls[i]);
        }
      }
    }
    if (isSerious == true) {
      for (int i = 0; i < filteredGirls.length; i  ) {
        if (filteredGirls[i].lookingFor.toLowerCase() != "serious") {
          filteredGirls.remove(filteredGirls[i]);
        }
      }
    }
    //filteredGirls = filteredGirls.toSet().toList();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: Column(
        children: [
          Padding(padding: EdgeInsets.all(20)),
          // ElevatedButton(
          //     onPressed: () {
          //       Navigator.push(context,
          //           MaterialPageRoute(builder: (context) => GenderScreen()));
          //     },
          //     child: Text("Go to Gender Screen")),
          // Padding(padding: EdgeInsets.all(30)),
          Text("Set max distance"),
          Padding(padding: EdgeInsets.all(10)),
          Slider(
            min: 1.0,
            max: 100.0,
            divisions: 100,
            activeColor: Colors.green,
            inactiveColor: Colors.orange,
            label: 'Set distance value',
            value: distance.toDouble(),
            onChanged: (value) {
              changeDistance(value);
            },
          ),
          Padding(padding: EdgeInsets.all(10)),
          Text("Current distance is $distance kms"),
          Padding(padding: EdgeInsets.all(10)),
          Text("Set max age"),
          Padding(padding: EdgeInsets.all(10)),
          Slider(
            min: 18.0,
            max: 60.0,
            divisions: 42,
            activeColor: Colors.green,
            inactiveColor: Colors.orange,
            label: 'Set age limit',
            value: age.toDouble(),
            onChanged: (value) {
              changeAgeLimit(value);
            },
          ),
          Padding(padding: EdgeInsets.all(10)),
          Text("Age limit is $age years"),
          Padding(padding: EdgeInsets.all(10)),
          Text("Sort by:"),

          Padding(padding: EdgeInsets.all(7.5)),
          ListTile(
            //minLeadingWidth: 30,
            title: Text("Age"),
            leading: Radio(
              value: "age",
              groupValue: sortCriterion,
              onChanged: (value) {
                setState(() {
                  sortCriterion = value.toString();
                  allGirls.sort((a, b) => a.age.compareTo(b.age));
                  populateFilteredGirls(distance, age);
                });
              },
            ),
          ),
          Padding(padding: EdgeInsets.all(7.5)),
          ListTile(
            //minLeadingWidth: 30,
            title: Text("Distance"),
            leading: Radio(
              value: "distance",
              groupValue: sortCriterion,
              onChanged: (value) {
                setState(() {
                  sortCriterion = value.toString();
                  allGirls.sort((a, b) => a.distance.compareTo(b.distance));
                  populateFilteredGirls(distance, age);
                });
              },
            ),
          ),
          Padding(padding: EdgeInsets.all(10)),
          Text("Is Single?"),
          Padding(padding: EdgeInsets.all(2.5)),
          InkWell(
            onTap: () {
              setState(() {
                isSingle = !isSingle;
                populateFilteredGirls(distance, age);
              });
            },
            child: (isSingle == false)
                ? Icon(Icons.check_box_outline_blank)
                : Icon(Icons.check_box),
          ),
          Padding(padding: EdgeInsets.all(5)),
          Text("Is Serious?"),
          Padding(padding: EdgeInsets.all(2.5)),
          InkWell(
            onTap: () {
              setState(() {
                isSerious = !isSerious;
                populateFilteredGirls(distance, age);
              });
            },
            child: (isSerious == false)
                ? Icon(Icons.check_box_outline_blank)
                : Icon(Icons.check_box),
          ),

          Padding(padding: EdgeInsets.all(10)),
          Expanded(
            child: ListView.builder(
              itemCount: filteredGirls.length,
              itemBuilder: (BuildContext context, int index) {
                return ListTile(
                  leading: const Icon(Icons.girl_outlined),
                  trailing: Text("${filteredGirls[index].distance} km away"),
                  title: Text("${filteredGirls[index].name}"),
                  subtitle: Text(
                      "${filteredGirls[index].age} years old, ${filteredGirls[index].status}, ${filteredGirls[index].lookingFor}"),
                  onTap: () {
                    // setState(() {
                    //   selectedGirlName = filteredGirls[index].name;
                    //   selectedGirlDistance = filteredGirls[index].distance;
                    // });
                    Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (context) => SelectedGirlDetails(
                                  girl: filteredGirls[index],
                                )));
                  },
                );
              },
            ),
          ),
          //Padding(padding: EdgeInsets.all(25)),
          //ElevatedButton(onPressed: () {}, child: Text("Check girl's details")),
          // Padding(padding: EdgeInsets.all(10)),
          // Text("Selected girl is: $selectedGirlName"),
          // Padding(padding: EdgeInsets.all(10)),
          // Text("$selectedGirlName is $selectedGirlDistance km away"),
        ],
      ),
    ));
  }
}

What is the error with my code and what is the solution?

CodePudding user response:

You can do this with a single query

List<Girls> filteredGirls = allGirls.where((element)=> element.age < 20 && element.distance < 10).toList();

CodePudding user response:

Let's check this loop carefully, Our looping will work i < filteredGirls.length

for (int i = 0; i < filteredGirls.length; i  ) {
  final x = filteredGirls[i].lookingFor.toLowerCase() != "serious";
  if (x) {
    filteredGirls.remove(filteredGirls[i]);
  }
}

Now for the first-case. We have three girls on filteredGirls.

i => 0;
filteredGirls.length => 3

First girl is Anika and she is serious and doesn't remove list

i => 1;
filteredGirls.length => 3

Now if Rupali is not serious we are removing the girl from filteredGirls.

i => 2;  
filteredGirls.length => 2  

i < filteredGirls.length breaks here

Now notice our initial list length was 3 and promised to loop on i < filteredGirls.length. After removing a single item, filteredGirls.length becomes 2. And loop breaks. And Monika stay on filter list.

To handle cases like this, create another list and store removable item, end of the loop remove items. And I prefer using like below and change others filter logic in this pattern.

if (isSerious == true) {
  List<Girls> removable = [];
  for (final g in filteredGirls) {
    if (g.lookingFor.toLowerCase() != "serious") {
      removable.add(g);
    }
  }
  for (final g in removable) {
    filteredGirls.remove(g);
  }
}
  • Related