I have just made a demo to clear what I want in my app
Like, I have a class model name Transaction and have some data like below
List<Transaction> transactionlist=[
Transaction(category: 'Food', amount: 100.00),
Transaction(category: 'Food', amount: 200.00),
Transaction(category: 'Shopping', amount: 1000.00),
Transaction(category: 'Shopping', amount: 2000.00),
Transaction(category: 'Food', amount: 300.00),
Transaction(category: 'Provision', amount: 500.00),
];
Now I want to show all category with its expense total , and therefor I have created a widget class...
class ShowCategoryStatus extends StatelessWidget {
final List<Transaction> transactionlist;
ShowCategoryStatus({required this.transactionlist});
List<Map<String,Object>> get amoutbycategory{
//what should I code here to get following list
/*this getter should return like following way
[
{
'Category':'Food','total':600
},
{
'Category':'Shopping','total':3000.00
},
{
'Category':'Provision','total':500
}
]
*/
}
CodePudding user response:
You can so this:
List<Transaction> result = [];
for (var e in transactionlist) {
var x = result.where((element) => element.category == e.category);
if (x.isEmpty) {
result.add(e);
} else {
var newTransaction = Transaction(
category: e.category, amount: x.first.amount e.amount);
result[result.indexOf(x.first)] = newTransaction;
}
}
Short Version: you can use collection package, and try this:
Map<String, List<Transaction>> grouped =
groupBy(transactionlist, (value) => value.category);
List<Transaction> result = grouped.entries
.map((e) => Transaction(
category: e.key,
amount: e.value.fold(0, (total, ele) => total ele.amount)))
.toList();
now if you print the result you will see what you want:
for (var element in result) {
print("result =${element.category} ${element.amount}");
// result =Food 600.0
// result =Shopping 3000.0
// result =Provision 500.0
}
CodePudding user response:
You could use a combination of groupBy
, map
and fold
:
List<Transaction> transactionlist = [
Transaction(category: 'Food', amount: 100.00),
Transaction(category: 'Food', amount: 200.00),
Transaction(category: 'Shopping', amount: 1000.00),
Transaction(category: 'Shopping', amount: 2000.00),
Transaction(category: 'Food', amount: 300.00),
Transaction(category: 'Provision', amount: 500.00),
];
Map<String, List<Transaction>> catGroup =
groupBy(transactionlist, (val) => val.category);
Map<String, double> amountMap = catGroup.map((key, value) =>
MapEntry(key, value.fold(0, (total, ele) => total ele.amount)));
print(amountMap);
The groupBy
is used to group all Transactions
by their category. map
is used to convert between Maps, and finally fold
is use to sum up all the amounts of a certain category. You could probably also use reduce
to sum the amounts here since the iterable should never be empty.
CodePudding user response:
hope you are fine,
Simple and slightly hard coded answer: you need to loop over list and check for category to sum amount and then return result.
void main() {
List<Transaction> transactions=[
Transaction(category: 'Food', amount: 100.0),
Transaction(category: 'Food', amount: 200.0),
Transaction(category: 'Shopping', amount: 1000.0),
Transaction(category: 'Shopping', amount: 2000.0),
Transaction(category: 'Food', amount: 300.0),
Transaction(category: 'Provision', amount: 500.0),
];
Transaction.amountByCategory(transactions);
print(Transaction.amountByCategory(transactions)
);
}
class Transaction{
String? category;
double? amount;
Transaction({this.category, this.amount});
static List<Map<String, dynamic>> amountByCategory(List<Transaction>
transactions) {
var foodAmount = 0.0;
var shoppingAmount = 0.0;
var provisionAmount = 0.0;
transactions.map((transaction) {
switch(transaction.category){
case "Food":
foodAmount = transaction.amount!.toDouble();
break;
case "Shopping":
shoppingAmount = transaction.amount!.toDouble();
break;
case "Provision":
provisionAmount = transaction.amount!.toDouble();
break;
}}).toList();
return [
{
"Category": "Food",
"total": foodAmount,
},
{
"Category": "Shopping",
"total": shoppingAmount,
},
{
"Category": "Provision",
"total": provisionAmount,
},
];
},
}
code link -> https://dartpad.dev/?
- hope I could help, have a nice day :)
CodePudding user response:
Best to way to do this, is put your logic out side of UI.
You can use extension
which are very powerful & useful for this kind of cases.
extension TransactionUtils on List<Transaction> {
List<Map<String, dynamic>> get categories {
// create a map for result
Map<String, double> totalAmounts = {};
forEach((transaction) {
totalAmounts.update(
transaction.category,
(oldAmount) => oldAmount transaction.amount,
ifAbsent: () => transaction.amount,
);
});
//? your data is ready
// {'Food': 600.0, 'Shopping': 3000.0, 'Provision': 500.0}
print(totalAmounts);
//? if you want list of map
// [
// {"category": "Food", "total": 600.0},
// {"category": "Shopping", "total": 3000.0},
// {"category": "Provision", "total": 500.0}
// ];
return totalAmounts.entries
.map((mapEntry) => {'category': mapEntry.key, 'total': mapEntry.value})
.toList();
}
}
& in your UI
you can use following way:
void main() {
final myData = transactionList.categories;
}
You can find detailed explanation about extension
on Vandad's blog.