Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Dart have something like `defaultdict` in Python?

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));
like image 610
dmjy Avatar asked Sep 06 '25 03:09

dmjy


2 Answers

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]}
}
like image 179
julemand101 Avatar answered Sep 07 '25 21:09

julemand101


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.

like image 29
jamesdlin Avatar answered Sep 07 '25 19:09

jamesdlin