Hi I am new to flutter and dart. I come from Java background. I am facing difficulty in typecasting maps. I have saved some data on Firestore in the format of Map<String,List<String>>. In my flutter app when I am fetching this data, I am getting it in the format of LinkedHashMap<dynamic,dynamic>. I want to convert this LinkedHashMap into a Map<String,List<String>>. I tried the Map.from() constructor but it is throwing exception type 'List<dynamic>' is not a subtype of type 'List<String>'. Following is the line where I am attempting to typecast this.
Map<String, List<String>> values = Map<String, List<String>>.from(documentSnapshot.data['Watchlist']);
Please let me know if any more information is needed.
First, this is not a support forum. Please use Stackoverflow or Gitter.im for support.
Second, use the map() method on LinkedHashMap to convert your LinkedHashMap
LinkedHashMap<dynamic,dynamic> linkedHashMap = LinkedHashMap<dynamic,dynamic>();
Map<String,List> map = linkedHashMap.map((a, b) => MapEntry(a as String, b as List));
Welcome to Dart!
Asking on Stack overflow is recommended because it makes your answer visible to more people, and it usually gives a quicker response, but there is nothing wrong with asking here.
In Java, generic type parameters are erased, so at run-time there is no difference between a Map<Object, Object> and a Map<String, Object> which has the same entries.
Dart retains type parameters at run-time. That allows Dart to do some operations that Java can't (or at least check their type correctly at run-time). However, it means that if you need a Map<String, dynamic>, you can't use a Map<dynamic, dynamic> directly because it has a different run-time type.
If you know that your Map<dynamic, dynamic> has only strings as keys, the simplest thing to do is:
var stringMap = map.cast<String, dynamic>();
This wraps the original map, and adds extra type checks on access.
Alternatively, you can create a new map with the same elements. Here
var stringMap = Map<String, dynamic>.from(map);
should work, but that doesn't change the element type.
In your case, you want the element type to be List<String>. However, the run-time type of the original map's values is List<dynamic>, so you also need to change the run-time list type, not just the map type.
For that, the map function suggested by @julemand101 is still a good choice:
var stringMap = map.map((key, value) => MapEntry(key as String, (value as List<dynamic>).cast<String>()));
assert(stringMap is Map<String, List<String>>);
This creates a new map, but merely casts (by wrapping) the lists.
Or you could create new lists instead:
var stringMap = map.map((key, value) => MapEntry(key as String, List<String>.from(value));
assert(stringMap is Map<String, List<String>>);
That obviously requires more copying up-front, but the resulting lists are faster to access because they don't have extra type checks from the cast wrapper. If performance is not critical, either approach should be fine.
(Since then we have also added improved map literals, and you can now write:
var stringMap = {for (var e in map.entries) e.key as String: List<String>.from(e.value)};
which is possibly easier to read).
@lrhn I am having the same issue in flutter when I try to use
var stringMap = map.map((key) => key as String, (value) => List<String>from(value));
assert(stringMap is Map<String, List<String>>);
i get an error " The argument type 'MapEntry
I can cast from map
@Yacine-Benali The map method on Map<K,V> requires a single function of type MapEntry<K2, V2> Function(K, V), not a function for keys and a function for values. So, the example above is wrong, I'll fix it.
So, you can write it as:
var stringMap = map.map((key, value) => MapEntry(key as String, List<String>.from(value)));
or (my new preference):
var stringMap = {for (var e in map.entries) e.key as String: List<String>.from(e.value)};
@lrhn Got a typo in last line: map.value > e.value
Good catch. Fixed.
Most helpful comment
First, this is not a support forum. Please use Stackoverflow or Gitter.im for support.
Second, use the map() method on LinkedHashMap to convert your LinkedHashMap to e.g. Map by typecasting each element of the LinkedHashMap. E.g.