Home > Enterprise >  how to sort data on base of date and avoid data repetition
how to sort data on base of date and avoid data repetition

Time:11-01

here is the list which i get from server `

[
  {
    "Name": "101 Working hours",
    "Balance": "8.00",
    "Date": "2022-10-19",
    "ShiftName": "AU128"
  },
  {
    "Name": "102 Bonus pay",
    "Balance": "3:48",
    "Date": "2022-10-19",
    "ShiftName": ""
  },
  {
    "Name": "110 Split Shift",
    "Balance": "1:00",
    "Date": "2022-10-19",
    "ShiftName": ""
  },
  {
    "Name": "111 Wage reduction",
    "Balance": "1:00",
    "Date": "2022-10-19",
    "ShiftName": ""
  },
  {
    "Name": "111 Wage reduction",
    "Balance": "1:00",
    "Date": "2022-10-20",
    "ShiftName": ""
  },
  {
    "Name": "101 Working hours",
    "Balance": "8.00",
    "Date": "2022-10-21",
    "ShiftName": "AU128"
  },
  {
    "Name": "102 Bonus pay",
    "Balance": "3:48",
    "Date": "2022-10-21",
    "ShiftName": ""
  },
  {
    "Name": "110 Split Shift",
    "Balance": "1:00",
    "Date": "2022-10-21",
    "ShiftName": ""
  },
  {
    "Name": "111 Wage reduction",
    "Balance": "1:00",
    "Date": "2022-10-21",
    "ShiftName": ""
  },
]

`

here you can see date is repeating and all i want to avoid date repetition on FE. you can see app Screenshot to get an idea which i get and which i want to achieve.

the data i get.

enter image description here

the data i want to be achieved

enter image description here

I tried to avoid date repetition and insert data on same list if date is same but all the time i get repetition date and data as you can see in image.

my code:

 Expanded(
          child: Consumer<EmployeeWageAccountsProvider>(
              builder: (context, data, child) {
            if (!data.isLoading) {
              int length = data.getEmployeeAccountsData!.length;
              if (data.getEmployeeAccountsData!.isNotEmpty) {
                wageAccountsData = data.getEmployeeAccountsData!;
                return ListView.builder(
                  itemCount: length,
                  shrinkWrap: true,
                  scrollDirection: Axis.vertical,
                  itemBuilder: (context, i) {
                    return WageAccountsCard(
                      date: Helper.formatStringDate(
                          wageAccountsData[i].date!),
                      balance: wageAccountsData[i].balance,
                      name: wageAccountsData[i].name,
                      shiftName: wageAccountsData[i].shiftName,
                    );
                  },
                );
              }
              return noDataFound(context, 50);
            }
            return const WageAccountsShimmer();
          }),
        )

wageacount card

class WageAccountsCard extends StatelessWidget {
  final String? date;
  final String? balance;
  final String? name;
  final String? shiftName;

const WageAccountsCard(
    {Key? key, this.date, this.name, this.balance, 
     this.shiftName})
    : super(key: key);

@override
  Widget build(BuildContext context) {
    return Container(
     margin: const EdgeInsets.all(10),
     padding: const EdgeInsets.all(8),
     decoration: CustomBoxDecoration.cardDecoration(context, 
  shadow: true),
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(
            shiftName!,
            style: wageTextStyle,
          ),
          Text(
            date.toString(),
            style: wageTextStyle,
          ),
        ],
      ),
      SizedBox(
        height: Styles.height(context) * 0.01,
      ),
      Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(
            S.of(context).wage_type,
            style: cTextStyle,
          ),
          Text(
            S.of(context).balance,
            style: cTextStyle,
          ),
        ],
      ),
      const Divider(
        color: Colors.black,
      ),
      Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(
            name!,
            style: cTextStyle,
          ),
          Text(
            balance.toString(),
            style: cTextStyle,
          ),
        ],
      ),
      SizedBox(
          height: Styles.height(context) * 0.01,
         ),
       ],
     ),
    );
  }
}

model class

class EmployeeWageAccountsModel {
   String? name;
   String? balance;
   String? date;
   String? shiftName;

   EmployeeWageAccountsModel({this.name, this.balance, this.date, 
 this.shiftName});

 EmployeeWageAccountsModel.fromJson(Map<String, dynamic> json) {
   name = json['Name'];
   balance = json['Balance'];
   date = json['Date'];
   shiftName = json['ShiftName'];
 }

Map<String, dynamic> toJson() {
   final Map<String, dynamic> data = <String, dynamic>{};
   data['Name'] = name;
   data['Balance'] = balance;
   data['Date'] = date;
   data['ShiftName'] = shiftName;
   return data;
  }
}

parsing data from API

List<EmployeeWageAccountsModel> employeeWageAccountsList =
  List<EmployeeWageAccountsModel>.from(
      employeeWageAccountsResponse.map((model) =>
          EmployeeWageAccountsModel.fromJson(model)));

CodePudding user response:

You could build a Map<String, List<Map<String, String>>> using forEach where key would be unique dates and values would be the list of objects.

void main() {
  const data = [
    {
      "Name": "101 Working hours",
      "Balance": "8.00",
      "Date": "2022-10-19",
      "ShiftName": "AU128"
    },
    {
      "Name": "102 Bonus pay",
      "Balance": "3:48",
      "Date": "2022-10-19",
      "ShiftName": ""
    },
    {
      "Name": "110 Split Shift",
      "Balance": "1:00",
      "Date": "2022-10-19",
      "ShiftName": ""
    },
    {
      "Name": "111 Wage reduction",
      "Balance": "1:00",
      "Date": "2022-10-19",
      "ShiftName": ""
    },
    {
      "Name": "111 Wage reduction",
      "Balance": "1:00",
      "Date": "2022-10-20",
      "ShiftName": ""
    },
    {
      "Name": "101 Working hours",
      "Balance": "8.00",
      "Date": "2022-10-21",
      "ShiftName": "AU128"
    },
    {
      "Name": "102 Bonus pay",
      "Balance": "3:48",
      "Date": "2022-10-21",
      "ShiftName": ""
    },
    {
      "Name": "110 Split Shift",
      "Balance": "1:00",
      "Date": "2022-10-21",
      "ShiftName": ""
    },
    {
      "Name": "111 Wage reduction",
      "Balance": "1:00",
      "Date": "2022-10-21",
      "ShiftName": ""
    },
  ];

  final Map<String, List<Map<String, String>>> dates = {};
  data.forEach((e) {
    if (dates.containsKey(e['Date'])) {
      dates[e['Date']]?.add(e);
    } else {
      dates[e['Date']!] = [e];
    }
  });

  dates.forEach((e, k) {
    print("$e\n${k.join("\n")}");
    print('\n');
  });
}

enter image description here

CodePudding user response:

One way to achive this is to use equatable package so you can compare objects

class Person extends Equatable {
  const Person(this.name,this.date);
  final String name;
  final DateTime date;
  @override
  List<Object> get props => [name,date];
}

now you can compare two objects of type Person and with a simple function you can remove the repetition . example:

List<Person> yourList = [];
// before you add new object check if its already available 
int getEqual(Person onePerson)=>yourList.indexWhere((element)=> element == onePerson);

if (getEqual(onePerson) != -1){
 // object was not found in the list
 yourList.add(onePerson);
}

// then sort your list by date using sort method
yourList.sort((a,b) => a.date.compareTo(b.date));

CodePudding user response:

You can use collection package and group your data with date :

var grouped = groupBy(xdata, (Map value) => value['Date']);

then you can make list base on grouped. Note that xdata is your list that you get from server.

grouped is map and contain this:

{
 2022-10-19: [
    {Name: 101 Working hours, Balance: 8.00, Date: 2022-10-19, ShiftName: AU128}, 
    {Name: 102 Bonus pay, Balance: 3:48, Date: 2022-10-19, ShiftName: }, 
    {Name: 110 Split Shift, Balance: 1:00, Date: 2022-10-19, ShiftName: }, 
    {Name: 111 Wage reduction, Balance: 1:00, Date: 2022-10-19, ShiftName: }
 ], 
 2022-10-20: [
    {Name: 111 Wage reduction, Balance: 1:00, Date: 2022-10-20, ShiftName: }
 ], 
 2022-10-21: [
    {Name: 101 Working hours, Balance: 8.00, Date: 2022-10-21, ShiftName: AU128}, 
    {Name: 102 Bonus pay, Balance: 3:48, Date: 2022-10-21, ShiftName: }, 
    {Name: 110 Split Shift, Balance: 1:00, Date: 2022-10-21, ShiftName: }, 
    {Name: 111 Wage reduction, Balance: 1:00, Date: 2022-10-21, ShiftName: }
 ]
}

also change your model class to this:

class EmployeeWageAccountsModel {
  String? date;
  String? shiftName;
  List<Wage>? wages;

  EmployeeWageAccountsModel({this.wages, this.date, this.shiftName});

  EmployeeWageAccountsModel.fromJson(Map<String, dynamic> json) {
    wages = (json.values.first as List).map((e) => Wage.fromJson(e)).toList();

    date = json.keys.first;
    shiftName = json.values.first[0]['ShiftName'];
  }

   ...  
}

class Wage {
  String? name;
  String? balance;
  Wage({this.name, this.balance});

  Wage.fromJson(Map<String, dynamic> json) {
    name = json['Name'];
    balance = json['Balance'];
  }
}

and parse it like this:

var grouped =
    groupBy(employeeWageAccountsResponse, (Map value) => value['Date']);

List<EmployeeWageAccountsModel> employeeWageAccountsList =
    List<EmployeeWageAccountsModel>.from(grouped.entries
        .map((e) => EmployeeWageAccountsModel.fromJson({e.key: e.value})));

then change your list item to this:

class WageAccountsCard extends StatelessWidget {
  final String? date;
  final String? shiftName;
  final List<Wage>? wages;

  const WageAccountsCard(
      {Key? key,
      this.date,
      this.shiftName,
      this.wages})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.all(10),
      padding: const EdgeInsets.all(8),
      decoration: CustomBoxDecoration.cardDecoration(context, shadow: true),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                shiftName!,
                style: wageTextStyle,
              ),
              Text(
                date.toString(),
                style: wageTextStyle,
              ),
            ],
          ),
          SizedBox(
            height: Styles.height(context) * 0.01,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                S.of(context).wage_type,
                style: cTextStyle,
              ),
              Text(
                S.of(context).balance,
                style: cTextStyle,
              ),
            ],
          ),
          const Divider(
            color: Colors.black,
          ),
          ListView.builder(
            itemBuilder: (context, index) {
              return Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    wages![index].name!,
                    style: cTextStyle,
                  ),
                  Text(
                    wages![index].balance.toString(),
                    style: cTextStyle,
                  ),
                ],
              );
            },
            itemCount: wages!.length,
            shrinkWrap: true,
          ),
          SizedBox(
            height: Styles.height(context) * 0.01,
          ),
        ],
      ),
    );
  }
}
  • Related