Dart how to access second dimension in multidimensional map - flutter

I can manage to access the first dimension with mymap['status'] but I tried to access the second dimension with mymap['status'].start or mymap['status']['start'] but neither work.
Also I don't see why mymap.status doesn't work for the first dimension?
const mymap = {
'status': {
'start': ['Start', 'ok', 'go'],
},
'update': {
'now': ['Start', 'ok', 'go'],
},
'time': [
['20', '10s', '5s'],
['45', '30s', '15s']
]
};
Also not sure whether this map should have the data type Map or not but with it I get no error signal with mymap['status'].start but upon executing the code it throws the error Class '_ImmutableMap<String, List<String>>' has no instance getter 'start'

To fix your issue use a static type Map after const , like this :
const Map mymap = {
'status': {
'start': ['Start', 'ok', 'go'],
},
'update': {
'now': ['Start', 'ok', 'go'],
},
'time': [
['20', '10s', '5s'],
['45', '30s', '15s']
]
};
print(mymap['status']['start']);
You can run the code if you want https://dartpad.dartlang.org/20eab4288fbf688c6517365b89fc2b22

You look up values for keys in a Dart Map using map[key]. If the key is a string, that would be mymap["status"]. You cannot use mymap.status because map keys are completely separate from class members. That's why you can do both map["length"] and map.length and get different results.
In your example, the static type of mymap is inferred to be Map<String, Object>.
This is inferred because the values of your map are either Map<String, List<String>> (for "status" and "update") or List<List<String>> (for "time"). The only common supertype of Map and List is Object, so your map is a Map<String, Object>.
When you then write mymap['status'] you get an expression with static type Object, and you are not allowed to do ['start'] on that (Object does not have an [] operator).
If you type your variable as Map<String, dynamic>, then you are allowed to do mymap['status']['start']. The final index operation is a dynamic invocation, which comes at some run-time cost.
Alternatively, you can do (mymap['status'] as Map<String, List<String>>)['start'] which casts the looked-up value to a map of the correct type, and then does a well-typed lookup on the that map.

Related

A value of type 'Map<String, Object>' can't be assigned to a variable of type 'HashMap<String, dynamic>' flutter

I am having a HashMap of <String, dynamic> and i would like to populate the map. The problem i am having is that its telling me the map is not of type dynamic. Below is my code
HashMap<String, dynamic> stuff1 = {"id": 1, "region": "North",
"shippingAddress": "Flyover", "list": []};
How can i create a HashMap of <String, dynamic>, i know some would suggest using HashMap<String, Object> stuff but i am having a list like below
List<HashMap<String, dynamic>>? stuffList;
which has data being populate from a server, but i just want to add stuff1 to the top of the list and i would like to add it with a HashMap of <String, dynamic> because if i add with <String, Object> it won't work
Dart Map literals (e.g. {"id": 1, "region": "North", ...} create objects that conform to the abstract Map interface. By default, the constructed objects are LinkedHashMap instances, but the static (known at compile-time) type of the literal is just Map.
Map is the abstract base type for a number of implementations (such as LinkedHashMap and HashMap). In general, you cannot directly assign a base type where a derived (more specific) type is expected; that might not be safe. You also can't just cast the object (which is LinkedHashMap) to a HashMap; neither LinkedHashMap nor HashMap derives from the other.
If you really want an unordered HashMap, you must use a HashMap constructor. For example:
HashMap<String, dynamic> stuff1 = HashMap.of({
"id": 1,
"region": "North",
"shippingAddress": "Flyover",
"list": [],
});
Alternatively consider using a regular Map (which, again, by default is a LinkedHashMap), which already is hash-based but which additionally maintains insertion order.
Try to explicitly instantiate HashMap
final Map<String, dynamic> stuff1 = HashMap()..addAll({"id": 1, "region": "North", "shippingAddress": "Flyover", "list": []});
The other solution might be possible is to as HashMap<String, dynamic> as the end of stuff1
Map<String, dynamic> stuff1 = {"id": 1, "region": "North", "shippingAddress": "Flyover", "list": []} as HashMap<String, dynamic>;

json_serializable flutter parse and map with key connect with modal and mapper

Thais is my json format
"recommended": {
"section_title": "Recommended",
"section_sub_title": "Recommended",
"data": {
"Allahabad": [
{
"gym_id": "9",
"name": "raga fitness",
"address": "35 Vivekanand Marg Hewett Road Allahabad",
"city_id": "1565",
"gym_logo": "http://139.180.218.66/gym/resources/alias_raga_fitness_20220403165957.jpeg",
"no_of_ratings": null,
"total_ratings": null,
"average_ratings": null,
"city_name": "Allahabad"
}
],
"Lucknow": [
{
"gym_id": "2",
"name": "Gym Name 2",
"address": "gym address",
"city_id": "1496",
"gym_logo": "http://139.180.218.66/gym/resources/alias_Gym_Name_20220127182703.jpeg",
"no_of_ratings": "16",
"total_ratings": "55.5",
"average_ratings": "3.5",
"city_name": "Lucknow"
}
]
}
}
i use json_serializable, dio, and json_annotation want to be mapped with modal and ResponseMapper
I am using json_serializable in Flutter to store a class in a file and read back from it. I am not posting the original class here for simplicity, but the principle is that half way through writing the app I decided that I wanted to change the variable name "aStupidName" to "name". How can I advise the code generation utility to assign the JSON value with the key "aStupidName", if it exists in the JSON, to the variable "name", but if the key "name" exists to assign this to the variable instead, i.e. in newer versions of the file?
Solution 1
In the model class, let's say XYZ, use the #JsonKey to map a how a field is read from JSON. This can be done with JsonKey.readValue that takes 2 arguments: the JSON data as Map<String, dynamic> and the field name. It's going to be something like the following. Also, check out the official docs.
import 'package:json_annotation/json_annotation.dart';
part 'xyz.g.dart';
Object? mapper(json, field) => json['name'] ?? json['aStupidName'];
#JsonSerializable(explicitToJson: true)
class XYZ {
#JsonKey(readValue: mapper)
String name;
XYZ({required this.name});
factory XYZ.fromJson(Map<String, dynamic> json) => _$XYZFromJson(json);
Map<String, dynamic> toJson() => _$XYZToJson(this);
}
I'd also recommend normalizing the API/DB/whatever itself to be always name so there is no need to annotate this way.
Solution 2
On the other hand, it's possible to implement the serialization/deserialization by hand like the following. Just use the ?? operator conditional expression between name and aStupidName.
#JsonSerializable()
class XYZ {
final String name;
...
XYZ.fromJson(Map<String, dynamic> json)
: name = json['name'] ?? json['aStupidName'],
...;
Map<String, dynamic> toJson() => {
'name': name,
...
};
}

Filter and manipulate a map

It's the first time I use Dart and I'm stuck with a simple thing.
I have a simple Map and I need to remove some items from this map and modify the content.
I have this:
Map<String, List<String>> dataset = {
'apple': ['apple1', 'apple2', 'apple3'],
'pear': ['pear1', 'pear2'],
'ananas': ['ananas1', 'ananas2', 'ananas3'],
'orange': ['orange1', 'orange2', 'orange3', 'orange4'],
};
List<Map<dynamic, String>> fruits = [
{'key': 'pear', 'labelToShow': 'Pear fruit'},
{'key': 'ananas', 'labelToShow': 'My ananas'},
];
and I would like to have this:
Map<String, Map<String, List<String>>> result = {
'pear': {
'values': ['pear1', 'pear2'],
'labelToShow': 'Pear fruit'
},
'ananas': {
'values': ['ananas1', 'ananas2', 'ananas3'],
'labelToShow': 'My ananas'
},
};
So, basically, I need to remove from dataset the items that have the key that it's not included in fruits (in field key) and then I need to add the field labelToShow.
I dont' know ho to do that.
I started removing items from dataset doing so:
dataset.removeWhere((k, v) => k != 'pear' && k != 'ananas');
but I don't like, I would like to loop through fruits.
Can someone please help me?
Thanks a lot
I wouldn't remove anything from dataset. Instead I'd build a new map from scratch, with just the data you want.
How about:
Map<String, Map<String, List<String>>> result = {
for (var fruit in fruits)
fruit["key"]: {
"values": dataset[fruit["key"]],
"labelToShow": fruit["labelToShow"]
}
};

How to remove an item from list of maps based on specific key?

I have the following list
List<Map<String, dynamic>> filterItems = [
{"category":1},
{"option_val":1},
]
I also have the following map
Map<String, dynamic> singleItem = {"category":6}
I would like to remove any item from the list above (filterItems) which has an object with key similar to singleItem map. So in my case i would like to remove the {"category":1} from the list since it has a key category similar to the map.
So i have tried the following
filterItems.remove(singleItem);
print(filterItems)
But the above doesnt work since the value of key is different so i tried the following where am now stuck on how to proceed
singleItem.map((key,value){
filterItems.removeWhere((element) => element.containsKey(key))
})
But the above throws an error that the body of singleItem.map is returning null. How can I proceed to remove an item from the list when a key matches even though the value is different?
you can use .removeWhere as follow:
List<Map<String, dynamic>> filterItems = [
{"category":1},
{"option_val":1},
];
Map<String, dynamic> singleItem = {"category":6};
filterItems.removeWhere((element) => element.keys.first == singleItem.keys.first);
print(filterItems);
and the result would be:
[{option_val: 1}]
Remove when a list has the same key
List<Map<String, dynamic>> filterItems = [
{"category": 1},
{"option_val": 1},
];
Map<String, dynamic> singleItem = {"category": 6};
filterItems = filterItems.where((e) {
return e.keys.toString() != singleItem.keys.toString();
}).toList();

Multi level Map or List of maps in dart?

I have a Map of location data like this :
{
'country': 'Japan',
'city': 'Tokyo',
'Latitude': 35.6762,
'Longitude': 139.6503,
'utcOffset': 9
}
witch is the right solution for storing this data and why ?
1) list of maps :
List<Map<String, dynamic>> locations = [
{
'country': 'Japan',
'city': 'Tokyo',
'Latitude': 35.6762,
'Longitude': 139.6503,
'utcOffset': 9
}
];
or multi level data object
var locations = {
{
'country': 'Egypt',
'city': 'Cairo',
'Latitude': 30.033333,
'Longitude': 31.233334,
'utcOffset': 2
},
{
'country': 'Thailand',
'city': 'Bangkok',
'Latitude': 13.7563,
'Longitude': 100.5018,
'utcOffset': 7
},
};
And how to access the data in the 2 cases?
I usually use Map when I want to have key-value pairs because I can directly get the value by key. As a example if you have Map of employes and if you keep the employee id as a key, you can easily access it. Specially for search, or for drop down this is elegant.
Most of the time if I can avoid Map and I will use List because it is very easy for me to handle large amount of data(In flutter I can throw a list to a ListView easily).
But both have there own greatness for depending on the scenario. And note that Map cannot have duplicate key, where List doesnt have like that limitation(Ex: Map can use to avoid duplicate).
var locations = {
{
'country': 'Egypt',
'city': 'Cairo',
'Latitude': 30.033333,
'Longitude': 31.233334,
'utcOffset': 2
},
{
'country': 'Thailand',
'city': 'Bangkok',
'Latitude': 13.7563,
'Longitude': 100.5018,
'utcOffset': 7
},
};
for (var element in locations) {
print(element["country"]);
}
// or
locations.forEach((element) => print(element["country"]));
Here what doc contains about this:
Map<K, V> class
A collection of key/value pairs, from which you retrieve a value using
its associated key.
There is a finite number of keys in the map, and each key has exactly
one value associated with it.
Maps, and their keys and values, can be iterated. The order of
iteration is defined by the individual type of map.
List<E> class
An indexable collection of objects with a length.
Subclasses of this class implement different kinds of lists. The most
common kinds of lists are:
Fixed-length list. An error occurs when attempting to use operations that can change the length of the list.
Growable list. Full implementation of the API defined in this class.
The default growable list, as returned by new List() or [], keeps an
internal buffer, and grows that buffer when necessary. This guarantees
that a sequence of add operations will each execute in amortized
constant time. Setting the length directly may take time proportional
to the new length, and may change the internal capacity so that a
following add operation will need to immediately increase the buffer
capacity. Other list implementations may have different performance
behavior.
You can use both but the first one is preferred as its easier to loop through the items and get the data out.
Not that you can't loop through the second data set, just that its more tedious to loop an array.
Given that your array of objects look like this:
List<Map<String, dynamic>> locations = [
{
'country': 'Japan',
'city': 'Tokyo',
'Latitude': 35.6762,
'Longitude': 139.6503,
'utcOffset': 9
}
];
Suppose you want to take out all the country names and store them in a separate array, It would be really easy and the code should look as follows:
List<String> countryNames = [];
locations.forEach((location) => countryNames.add(location['country]));
You can get data dynamically from a Map creating a this function getData
dynamic getData(Map data, List<String> way) {
dynamic dataTemp = data;
if (way.length > 0) {
for (int x=0; x < way.length; x++) {
dataTemp = dataTemp[way[x]];
}
}
return dataTemp;
}
List<Map<String, dynamic>> locations = [
{
'country': 'Japan',
'city': 'Tokyo',
'Latitude': 35.6762,
'Longitude': 139.6503,
'utcOffset': 9,
'example' : {
'data' : "text",
'number' : 20,
'boolean': false
}
}
];
getData(locations[0],["example","number"]);
output: 20