0

I need a multidimensional array/list (2 and/or 3 dimensions) which must contains different objects. This is what I found:

  List recipes = List.generate(
      999,
      (_) => List<Ingredient>.filled(
          9,
          Ingredient(
              name: '', carboidrates: 0, proteins: 0, lipids: 0, fibers: 0),
          growable: true));

My needs is to have recipes[index/int][index/Ingredient].somethingoftheIngredientClass

As for example, if I create a single List:

List<Ingredient> recipe = <Ingredient>[];

I can access the class as

recipe[0].carboidrates

Not the same for my 2 dimensional list:

recipes[0][0].doesnotshowCarboidrates
2
  • maybe using Map is the right choice for your case. Commented Nov 28, 2022 at 23:12
  • Yes, maybe. I'll check. Commented Nov 28, 2022 at 23:32

3 Answers 3

1

A list or multi-dimensional lists can only have a single type. Looking at your sample code, it looks like you're trying to associate ingredients and properties of a given recipe to a recipe using a multi-dimensional list.

A better approach would be to use classes. Classes will give you a more structured design and a little more flexibility. For example, the code below overrides the equality operator (==) and hashCode to be able to compare recipes and find a given recipe in a list.


class Recipe {
  final String name;
  final List<Ingredient> ingredients;
  final List<Instruction> instructions;

  Recipe({
    required this.name,
    required this.ingredients,
    required this.instructions,
  });

  @override
  bool operator ==(Object other) =>
      identical(this, other) || other is Recipe && runtimeType == other.runtimeType && name == other.name;

  @override
  int get hashCode => name.hashCode ^ ingredients.hashCode ^ instructions.hashCode;
}

class Ingredient {
  final String name;
  final String description;

  Ingredient({
    required this.name,
    required this.description,
  });
}

class Instruction {
  final String description;
  final String? tip;

  Instruction({
    required this.description,
    this.tip,
  });
}

final recipes = [
  Recipe(
    name: 'Cheese pizza',
    ingredients: [
      Ingredient(name: 'Dough', description: 'Normal yeast based pizza dough'),
      Ingredient(name: 'Tomato Sauce', description: 'Freshly blended organic tomatoes'),
      Ingredient(name: 'Mozzarella Cheese', description: 'Cheesy cheesiness from mount cheese'),
    ],
    instructions: [
      Instruction(description: 'Preheat oven to 400 degrees Fahrenheit'),
      Instruction(description: 'While oven is preheating spread dough evenly in a circle over an oiled pan'),
      Instruction(description: 'Spread sauce evenly over dough leaving enough room for the crust'),
      Instruction(description: 'Cover the sauce with the Mozzarella cheese'),
      Instruction(
        description: 'Roll the edge of the dough to form the crust',
        tip: 'Optionally add cheese within the dough for stuffed crust!',
      ),
      Instruction(description: 'Bake the pizza in the over until golden brown'),
      Instruction(
        description: 'Remove the pizza from the oven and let cool',
        tip: 'Some people like to let the pizza cool before cutting',
      ),
    ],
  ),
];

/// Find the index of a recipe. This uses the equality and hashcode overrides of the recipe class.
int getRecipeIndex(Recipe recipe) => recipes.indexOf(recipe);

/// Find all of the recipes containing the [query] in their name (case-insensitive).
List<Recipe> getRecipeByName(String query) {
  return recipes.where((element) => element.name.toLowerCase().contains(query.toLowerCase())).toList();
}

/// Get the ingredients of a recipe.
final recipeIngredients = recipes[0].ingredients;

/// Get the instructions of a recipe.
final recipeInstructions = recipes[0].instructions;

/// Get a list of all of the tips for a recipe.
final recipeTips = recipes[0].instructions.map((e) => e.tip).whereType<String>();

If for whatever reason you wanted to associate a recipe with a list of recipes (e.g. similar recipes) I would use a map of Recipe to List<Recipe>.

final pizza = recipes[0];

/// How to associate a recipe with similar recipes using a map of `Recipe` to `List<Recipe>`
final similarRecipesMap = { pizza: [recipes[1], recipes[2]]};

final similarRecipesToPizza = similarRecipesMap[pizza];

Hope that helps!

Sign up to request clarification or add additional context in comments.

4 Comments

My App is a Calories/Counter. I'm trying to maximize code performance and compact. I also need list to populate some ListView Builders. The app has 3 recipe 5 times per day. Really complex to explain but I will certainly need 3 dimensional list. As for example I use an AlertDialog to create a new ingredient and I would like to use a Tab Index to automatic insert in the correct list (to iterate too). In my mind 3d list it's perfect, probably because I don't know very well maps. Thanks for your great works that I will absolutely study.
As to explain more, the app will have two types of tabs (5 tabs for: breakfast, snack, lunch, snack, dinner), (3 tabs for 3 recipes for each first tabs). By using 3d list I can always know where to put data (and where to read) and iterate too (for builders). One piece of code can now move (write/read) on the whole app.
That's great. Thank you for the explanation and good luck on your app! :)
Finally, Map object is what I looking for... Many thanks
0

Just found a programming 'bug'.

I tried to replicate my exactly code:

  List recipes = List.generate(
      999,
      (_) => List<Ingredient>.filled(
          9,
          Ingredient(
              name: 'Cheesecake',
              carboidrates: 0,
              proteins: 0,
              lipids: 0,
              fibers: 0),
          growable: true));

As you can see by adding 'Cheesecake' as the name.

In Init functions I just tried this:

print(recipes[0][0].name);

This work as expected, I accessed the value correctly...

Console Output:

Restarted application in 262ms.
flutter: Cheesecake

Really don't know why when I arrive at this point:

print(recipes[0][0].

Visual Studio Code does not show Class/Ingredient properties*, however it works!

*It shows only:

hashCode, runtimeType, toString(), noSuchMethod(...)

Really hope someone should explain why...

1 Comment

Your call to print(recipes[0][0]) is going to invoke the toString() method on your Ingredient class. You can override this method to print all of the information you'd like to show in the console. For example: stackoverflow.com/a/64836405/563509 .
0

Yup, another practical way to have 2d/3d list:

eg a 3d example:

  List<List<List<Ingredient>>> ingredient =
      List.generate(999, (index) => [[]], growable: true);

On Init function:

ingredient[0][0].clear();
ingredient[0][0].add(Ingredient(
    name: 'Panettone', carboidrates: 0, proteins: 0, lipids: 0, fibers: 0));
print(ingredient[0][0][0].name);

And now when I arrive here:

print(ingredient[0][0][0].

I finally should see the Ingredient Class properties (like name, carboidrates... and so on!)... WIN!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.