Does Dart have something like `defaultdict` in Python?

473

Solution 1

You can use the putIfAbsent method on Map to create and insert e.g. an empty list to the map if it does not already exists: https://api.dart.dev/stable/2.7.2/dart-core/Map/putIfAbsent.html

void main() {
  Map<String, List<int>> m = {};

  m.putIfAbsent('001', () => []).add(1);
  m.putIfAbsent('001', () => []).add(2);
  m.putIfAbsent('002', () => []).add(3);

  print(m); // {001: [1, 2], 002: [3]}
}

Alternative solution

If you are going to use this pattern a lot it can be easier to just implement your own Defaultdict class which is not that complicated since we just want it to behave like a Map:

import 'dart:collection';

class Defaultdict<K, V> extends MapBase<K, V> {
  final Map<K, V> _map = {};
  final V Function() _ifAbsent;

  Defaultdict(this._ifAbsent);

  @override
  V operator [](Object? key) => _map.putIfAbsent(key as K, _ifAbsent);

  @override
  void operator []=(K key, V value) => _map[key] = value;

  @override
  void clear() => _map.clear();

  @override
  Iterable<K> get keys => _map.keys;

  @override
  V? remove(Object? key) => _map.remove(key);
}

void main() {
  // Create a Defaultdict where we return a empty new list for unknown keys
  final m = Defaultdict<String, List<int>>(() => []);

  m['001'].add(1);
  m['001'].add(2);
  m['002'].add(3);

  print(m); // {001: [1, 2], 002: [3]}
}

Solution 2

I usually use ??= when possible:

var m = <String, List<DataObject>>{};
(m['001'] ??= []).add(DataObject(something: something));
(m['002'] ??= []).add(DataObject(something: something));

Note that this isn't quite the same as using putIfAbsent since it will overwrite entries where the key exists but the value is null. If you never store null in your Map, then use whichever you think is cleaner.

Share:
473
dmjy
Author by

dmjy

Japanese in China

Updated on December 19, 2022

Comments

  • dmjy
    dmjy over 1 year

    What I want to do is this below. Could you teach me how to do this if possible?

    import 'package:my_package/data_object.dart';
    Map<String, List<DataObject>> m = Map<int, List<DataObject>>(); // Create an empty map.
    m['001'].add(DataObject(something: something)); // Can add DataObject without checking if '001' exists.
    m['002'].add(DataObject(something: something));
    
  • julemand101
    julemand101 about 4 years
    Updated with alternative solution with defaultdict class example.
  • julemand101
    julemand101 over 2 years
    Updated alternative solution to null-safety.