sortingdictionarydartkeysplay-tree

Looping over a SplayTreeMap doesn't give values with duplicated keys


I have a SplayTreeMap of players with their levels, and I wanna print a ranking of these players based on their level.

When I use .forEach to iterate over this SplayTreeMap, it ignores the players with the same level (means that while looping over SplayTreeMap, it doesn't take into consideration values with duplicated keys).

Here is my code:

SplayTreeMap<int, String> map = SplayTreeMap<int, String>();
    map[5] = 'player1';
    map[2] = 'player2';
    map[6] = 'player3';
    map[7] = 'player4';
    map[7] = 'player5';
    map[7] = 'player6';
    map.forEach((level, player) {
      print('$player -> $level');
    });

Here is the output of this code:

player2 -> 2
player1 -> 5
player3 -> 6
player6 -> 7

So I'm asking myself why it doesn't print player4 and player5.

If there is no solution to this, what's the best alternative to SplayTreeMap, to have a map, that's sorted based on its keys


Solution

  • A SplayTreeMap is a type of Map, and Maps cannot have duplicate keys:

    There is a finite number of keys in the map, and each key has exactly one value associated with it.

    (There are Map-like classes such as package:quiver's Multimap, but they cannot derive from Map since they must provide a different signature for some methods (e.g. operator []).)

    If you want a SplayTreeMap with multiple values for a single key, then you should store Lists as the values. For example:

    import 'dart:collection';
    
    extension SplayTreeMultiMapExtension<K, V> on SplayTreeMap<K, List<V>> {
      void add(K key, V value) {
        (this[key] ??= []).add(value);
      }
    }
    
    void main() {
      var map = SplayTreeMap<int, List<String>>();
      map.add(5, 'player1');
      map.add(2, 'player2');
      map.add(6, 'player3');
      map.add(7, 'player4');
      map.add(7, 'player5');
      map.add(7, 'player6');
    
      map.forEach((level, players) {
        for (var player in players) {
          print('$player -> $level');
        }
      });
    }
    

    Prints:

    player2 -> 2
    player1 -> 5
    player3 -> 6
    player4 -> 7
    player5 -> 7
    player6 -> 7
    

    Note that the above implementation allows duplicate players within each level. If you don't want that, you can use a Set<String> instead of a List<String>, or you can use a SplayTreeSet<String> if you want the players to be sorted within each level.