Billy Joseph
Billy Joseph

Reputation: 35

How to group a list by multiple values in dart

Let's say I have this list:

List<MoveItem> _items = [
MoveItem(
  shelf: A01,
  itemName: 'Dumpling',
  quantity: 3,
  expiryDate: DateTime(2021, 12, 8),   
),
MoveItem(
  shelf: A02,
  itemName: 'Dumpling',
  quantity: 3,
  expiryDate: DateTime(2021, 12, 8),     
),
MoveItem(
  shelf: A03
  itemName: 'Dumpling',
  quantity: 3,
  expiryDate: DateTime(2022, 01, 8),     
),
MoveItem(
  shelf: A04,
  itemName: 'Meatball',
  quantity: 3,
  expiryDate: DateTime(2022, 02, 8),     
),
MoveItem(
  shelf: A05,
  itemName: 'Meatball',
  quantity: 3,
  expiryDate: DateTime(2022, 02, 8),      
),];

How do I group the list by itemName AND expiryDate?

EDIT:

Using usual ListView.builder and intl package like this:

ListView.builder(
                itemCount: _items.length,
                itemBuilder: (ctx, i) =>                      
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text(
                          _items[i].itemName,
                        ),
                        Text(DateFormat('yyyy-MM-dd')
                            .format(_items[i].expiryDate)),
                        Text(
                          _items[i].quantity.toString(),
                        )]),

I would get this:

Dumpling    2021-12-8   3
Dumpling    2021-12-8   3
Dumpling    2022-01-8   3
Meatball    2022-02-8   3
Meatball    2022-02-8   3

The outcome I need:

Dumpling    2021-12-8   6
Dumpling    2022-01-8   3
Meatball    2022-02-8   6

I also need to pass the data of each group down the widget tree.

Using collection package, I could only group them by itemName OR expiryDate.

Upvotes: 2

Views: 3406

Answers (1)

Vitor
Vitor

Reputation: 840

Welcome to Stack Overflow.

You can group them using the item name and the date since these values you want to be the same:

  Map<String, MoveItem> groups = {};

  for (MoveItem item in _items) {
    String convertedDateTime =
        "${item.expiryDate.year.toString()}-${item.expiryDate.month.toString().padLeft(2, '0')}-${item.expiryDate.day.toString().padLeft(2, '0')}";
    if (groups[item.itemName + ' ' + convertedDateTime] == null)
      groups[item.itemName + ' ' + convertedDateTime] = MoveItem(
        expiryDate: item.expiryDate,
        quantity: item.quantity,
        itemName: item.itemName,
      );
    else
      groups[item.itemName + ' ' + convertedDateTime].quantity += item.quantity;
  }

Output:

{
   Dumpling 2021-12-08:Dumpling - 2021-12-08 6,
   Dumpling 2022-01-08:Dumpling - 2022-01-08 3,
   Meatball 2022-02-08:Meatball - 2022-02-08 6
}

My model:

class MoveItem {
  String itemName;
  int quantity;
  DateTime expiryDate;
  MoveItem({this.itemName, this.quantity, this.expiryDate});

  @override
  String toString() {
    String convertedDateTime =
        "${expiryDate.year.toString()}-${expiryDate.month.toString().padLeft(2, '0')}-${expiryDate.day.toString().padLeft(2, '0')}";
    return itemName + ' - ' + convertedDateTime + ' ' + quantity.toString();
  }
}

EDIT:

To use in a ListView.builder, it's easier to use a list for that:

  List<MoveItem> groups = [];

  for (int i = 0; i < _items.length; i++) {
    bool groupExists = false;
    for (MoveItem group in groups) {
      if (group.itemName == _items[i].itemName &&
          group.expiryDate == _items[i].expiryDate) {
        group.quantity += _items[i].quantity;
        groupExists = true;
      }
    }
    if (!groupExists) {
      groups.add(_items[i]);
    }
  }

Output:

[Dumpling - 2021-12-08 6, Dumpling - 2022-01-08 3, Meatball - 2022-02-08 6]

Using it in a ListView:

ListView.builder(
  itemCount: groups.length,
  itemBuilder: (ctx, i) => Row(
    mainAxisAlignment: MainAxisAlignment.spaceBetween,
    children: [
      Text(
        groups[i].itemName,
      ),
      Text(DateFormat('yyyy-MM-dd')
          .format(groups[i].expiryDate)),
      Text(
        groups[i].quantity.toString(),
      )
    ],
  ),
),

Upvotes: 2

Related Questions