skip to Main Content

Simple Map here:

Map map = Map<int, String>{};

I can populate it:

map = {1: 'c', 2: 'dart', 3: 'flutter'};

Here I need to specify a KEY. I would like to know on how to get an auto key.

I cannot use map.lenght because whenever I will delete e.g. the second item (2) the third will remain 3 and map.lenght will overwrite that key.

As the @eamirho3ein answer I tried this:

  //& Maps
  Map map = <int, Ingredient>{};


Map<int, T> addToMap<T>(Map<int, T> map, T newItem) {
  var list = map.entries.map((e) => e.value).toList();
  list.add(newItem);
  var newIndex = 1;

  return Map.fromIterable(list,
      key: (item) => newIndex++, value: (item) => item);
}


Map<int, Ingredient> result = addToMap<Ingredient>(
                            map, //Error here
                            Ingredient(
                                name: "Pizza",
                                kcal: 100,
                                carbohydrates: 50,
                                proteins: 35,
                                lipids: 23,
                                fibers: 12,
                                date: DateTime.now(),
                                bottomTabIndex: 0,
                                leftTabIndex: 0));

But I receive this error on map(indicated):

The argument type ‘Map<dynamic, dynamic>’ can’t be assigned to the
parameter type ‘Map<int, Ingredient>’.

This is my simple class:

class Ingredient {
  String? name;
  int? kcal;
  int? carbohydrates;
  int? proteins;
  int? lipids;
  int? fibers;
  int? leftTabIndex;
  int? bottomTabIndex;
  DateTime? date;

  Ingredient(
      {this.name,
      this.kcal,
      this.carbohydrates,
      this.proteins,
      this.lipids,
      this.fibers,
      this.leftTabIndex,
      this.bottomTabIndex,
      this.date});
}

5

Answers


  1. Chosen as BEST ANSWER

    Maybe I should use a function:

    int getNewKey(Map map) {
      if (map.isEmpty) {
        return 0; // or 1, this is the first item I insert
      } else {
        return map.keys.last + 1;
      }
    }
    

    And use it whenever I will add something to that map:

    {getNewKey(map) : 'c', getNewKey(map) : 'dart', getNewKey(map) : 'flutter'}

    Please let me know if this is faulty :-|

    By this way I will never overwrite a key that's only incremental.

    Please note: I should not use directly

    {(map.keys.last + 1) : 'c', (map.keys.last + 1) : 'dart', (map.keys.last + 1) : 'flutter'}
    

    Because if the Map is empty will produce an error.


  2. You can use an incrementing index key that will be always different than others on every call, and wrapping it inside an autoKey() method like this:

    int index = 0;
    autoKey() {
      return ++index;
    }
    
    Map<int, String> map = {};
    map = {autoKey(): 'c', autoKey(): 'dart', autoKey(): 'flutter'};
    
    print(map); {1: c, 2: dart, 3: flutter}
    
    Login or Signup to reply.
  3. You can use this function to remove an item in a map and auto generate new key:

    Map<int, T> removeFromMap<T>(Map<int, T> map, int index) {
        var list = map.entries.map((e) => e.value).toList();
        list.removeAt(index);
        var newIndex = 1;
    
        return Map.fromIterable(list,
            key: (item) => newIndex++, value: (item) => item);
      } 
    

    you can use it like this:

    var result = removeFromMap<String>({1: 'c', 2: 'dart', 3: 'flutter'}, 1);
    print("result = $result"); //result = {1: c, 2: flutter}
    

    If you want add new Item:

    Map<int, T> addToMap<T>(Map<int, T> map, T newItem) {
        var list = map.entries.map((e) => e.value).toList();
        list.add(newItem);
        var newIndex = 1;
    
        return Map.fromIterable(list,
            key: (item) => newIndex++, value: (item) => item);
      }
    

    and call it like this:

    var result = addToMap<String>({1: 'c', 2: 'dart', 3: 'flutter'}, 'B');
    print("result = $result"); //result = {1: c, 2: dart, 3: flutter, 4: B}
    
    Login or Signup to reply.
  4. another way is that you can use a class as key that never equals itself using hashCode, like this:

    class nonEqualKey {
      
      @override
      int get hashCode => 0;
      
      @override
      operator ==(covariant nonEqualKey other) {
        return other.hashCode != hashCode;
      }
      @override
      toString() {
        return "unique";
      }
    }
    
    Map map = {};
    map = {nonEqualKey(): 'c', nonEqualKey(): 'dart', nonEqualKey(): 'flutter'};
    print(map); // {unique: c, unique: dart, unique: flutter}
    

    Here I overridden the hashCode so it will be always 0, then I overridden the == operator so the objects can be equal if they have a different hashCode which is impossible since always 0!=0 is false.

    Even if you use the same class constructor, they will never be the same, and so, it lets you use it as much as you want without needing to handle it for every operation you will do on the Map

    Login or Signup to reply.
  5. If you have a Map that uses contiguous, integer-based keys, you should ask yourself if you should be using a List instead, and then you don’t need to manage keys yourself.

    If you must use a Map because some API requires it, you can still start with a List and then use List.asMap to easily convert it:

    var map = [
        'c',
        'dart',
        'flutter',
      ].asMap();
    
    print(map); // Prints: {0: c, 1: dart, 2: flutter}
    

    Note that List.asMap returns an unmodifable view, so if you want to allow mutation, you would need to create a copy:

    var map = Map.of([
        'c',
        'dart',
        'flutter',
      ].asMap());
    

    If must have your Map keys be integers starting from 1 and not 0, then you could insert a dummy element (and remove it later if desired):

    var map = Map.of([
        '',
        'c',
        'dart',
        'flutter',
      ].asMap())
        ..remove(0);
    
    print(map); // Prints: {1: c, 2: dart, 3: flutter}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search