I'm trying to iterate over the following data structure: {String: [{String, List<SomethingResponse>}]} where SomethingResponse = {String: dynamic}). I created this model:
class SomethingsResponse {
final Map<String, List<SomethingResponse>> SomethingsResponse;
SomethingsResponse({this.SomethingsResponse});
factory SomethingsResponse.fromJson(data) {
return SomethingsResponse(SomethingsResponse: data.map<String, List<SomethingResponse>>((String key, dynamic value) {
final dataFromCategory = List<SomethingResponse>.from(value.map((x) => SomethingResponse.fromJson(x)));
return MapEntry(key, dataFromCategory);
}));
}
}
When I try getting the keys like this: data.somethingsResponse.toList(), I get an error saying:
Class '_InternalLinkedHashMap<String, List>' has no instance method 'toList'.
I can't iterate over it or really get any kind of data out of it. What am I doing wrong and how can I fix it? I have a feeling the issue is at this line return MapEntry(key, dataFromCategory);, but I tried creating a Map a couple of different ways, and none worked.
If you consult the documentation for Map, you will see that it does not derive from Iterable and therefore cannot be directly iterated over. I presume that this is because it's not obvious what you want to iterate over: keys, values, or key-value pairs?
If you want to iterate over keys, use Map.keys. (In your case: data.somethingsResponse.keys.toList())
If you want to iterate over values, use Map.values.
If you want to iterate over key-value pairs (i.e. MapEntry objects), use Map.entries.
Related
I want to have a method that takes a parameter of type enum as a parameter and then operates on it to get all possible values of the enum type, and do some work with each of those values.
I'd be hoping for something like:
Widget foo (EnumType enumType) {
for(var value in enumType.values) {
print(value.name);
}
}
I've looked for solutions but the only ones I can find are addressed by passing a list of the values as a parm, however this doesn't solve my problem as, even with the list of objects, I can't know that they are enum values so if I try do the .name operation on them, dart throws an error Error: The getter 'name' isn't defined for the class 'Object'.
Maybe my only problem is that I don't know how to specify a variable as an EnumType but I haven't been able to find a correct type for this.
EnumType.values is the equivalent of an automatically generated static method on EnumType and as such is not part of any object's interface. You therefore will not be able to directly call .values dynamically.
I've looked for solutions but the only ones I can find are addressed by passing a list of the values as a [parameter], however this doesn't solve my problem as, even with the list of objects, I can't know that they are enum values so if I try do the .name operation on them, dart throws an error
You can use a generic function that restricts its type parameter to be an Enum:
enum Direction {
north,
east,
south,
west,
}
List<String> getNames<T extends Enum>(List<T> enumValues) =>
[for (var e in enumValues) e.name];
void main() {
print(getNames(Direction.values)); // Prints: [north, east, south, west]
}
The problem with enums is that they can't be passed as a parameter, what you can do instead is that pass all the values and then extract the name from the toString method.
void printEnumValues<T>(List<T> values){
for(var value in values){
final name = value.toString().split('.')[1];
print(name);
}
}
Also I would recommend you look into freezed union classes as that might allow you an alternative approach towards the problem you're trying to solve.
I have the following lists
List<ProductVariation> _productVariations = []; avoid null pointer exceptions
List<ProductVariation> get productVariations => _productVariations;
The main goal for adding List<ProductVariation> get productVariations => _productVariations; was to avoid _productVariations to be modified, however, I'm able to add, delete or do any operations inside the list, how can I prevent productVariations to be modified when accessed from another file?
An alternative solution is to use UnmodifiableListView from dart:collection which can be a lot more efficient since you are not making a new copy of the list but are instead just serving a protected view of your List:
import 'dart:collection';
class A {
final List<int> _data = [1, 2, 3];
UnmodifiableListView<int> get data => UnmodifiableListView(_data);
}
void main() {
final a = A();
print(a.data); // [1, 2, 3]
a.data.add(5); // Unhandled exception: Unsupported operation: Cannot add to an unmodifiable list
}
A downside of this solution is that UnmodifiableListView is a normal List seen from the analyzers point of view so you will not get any statically errors from doing this. But you will get an exception on runtime if you try modify the list itself. For making it more clear for the developer I think it is nice to specify that the returned type is UnmodifiableListView even if you could just write List instead.
Another point is that this solution (or the one suggested by Jigar Patel) does not prevents you from modifying the objects itself in the list if the objects are not immutable. So if you also want to prevent these changes you need to make deep copies of the objects.
You can make the getter return a copy of the list like this.
List<ProductVariation> get productVariations => [..._productVariations];
Or
List<ProductVariation> get productVariations => _productVariations.toList();
I got this code from the internet and I can not seem to understand it or find anything on the internet for it.
In the code below toMap is a method that returns 2 items, How is that possible?
And what is fromMap, is it a user created method? I thought methods used {} or => so it is a bit confusing.
Also, what is the key here for the Map? Can the map only store 2 categories of items? One is the key and the other is the value. Or it can have one key but multiple categories of values.
For example, there might be a single unique key, which could help take out the task title, time, reminder data, notes, etc as values of the map.
class Task {
String title;
bool completed;
Task({
this.title,
this.completed = false,
});
Task.fromMap(Map<String, dynamic> map): title = map['title'],completed = map['completed'];
updateTitle(title) {
this.title = title;
}
Map toMap() {
return {
'title': title,
'completed': completed,
};
}
}
In the code below toMap is a method that returns 2 items, How is that
possible?
No, it returns a Map (with two items). More about maps can be found here.
And what is fromMap, is it a user created method? I thought methods
used {} or => so it is a bit confusing.
Task.fromMap(Map<String, dynamic> map) is called "named constructor". The : title = map['title'],completed = map['completed'] part is initializer list
My understanding is;
In fromMap, you retrieve the title and completed from some map, and save it in your local variables.
In the toMap you take the saved values in your local variables and can return a Map.
The key is whatever you put you chose it to be, but here you chose one key to be titleand one to be completed.
Does this help you?
First of all we discuss about FormMap So what is fromMap()?
whenever you have any api and at firetime you will get json format so when you want to convert that data into any class format then you have to do like
Map temp = json.decode(response.body);
so your function can understand map key and retrieve that value and set in class local variable
and now Second point is toMap So what is toMap()?
Whenever you want to post something into api or somewhere you have map data so you can post in api
like
Abc a = Abc(name:"hari",address:"india");
a.toMap();
I'm parsing some JSON to read stored data into custom objects. I've implemented this simply using jsonDecode from dart:convert and writing a fromJson() constructor method on each of my custom objects. They're nested - so a TopicList object has a property which is a List<Topic>. I've written the fromJson() constructor on both TopicList and Topic, and I'm trying to use map to take the decoded JSON string and create an object from it. But it's failing because the list that map returns is of the wrong type, despite it being created from constructor methods.
class TopicList {
List<Topic> topics;
TopicList() {}
TopicList.fromJson(String jsonTopicList) {
Map decoded = jsonDecode(jsonTopicList);
// this *doesn't* work
topics = decoded['topics'].map((t) => Topic.fromJson(t)).toList();
// this does work
topics = [];
for (Map<String,dynamic> t in decoded['topics']) {
Topic newT = Topic.fromJson(t);
topics.add(newT);
}
}
}
class Topic {
String topic;
Topic({this.topic});
Topic.fromJson(Map<String, dynamic> t) {
this.topic = t['topic'];
}
}
When I try/catch the map method it tells me that the map().toList() call is returning a List<dynamic> rather than List<Topic>.
The reality is more complex than this with a further level (another List of other objects belonging to Topic) and with other properties. But this is the core of what is going on.
I'm not interested in workarounds - I've got one of those, which is working in the code above. But I want to understand why seemingly an object's constructor - in this example, it's Topic.fromJson() - is returning a dynamic object rather than a Topic.
Give a type argument to .map().
topics = decoded['topics'].map<Topic>((t) => Topic.fromJson(t)).toList();
Change
topics = decoded['topics'].map((t) => Topic.fromJson(t)).toList();
to
topics = decoded['topics'].map<Topic>((t) => Topic.fromJson(t)).toList();
That way, map will return an iterator of Topic which toList will convert to a list.
When I write like this
List.<Dictionary.<String, System.Object>>,
the ide tells me
Assets/Scripts/yhj/Model/PrintItem.js(23,71): BCE0044: expecting >, found '>>.
How can I resolve it?
Why would you make a list of dictionaries? Can't you just use the dictionary as the list with the key, value input instead of this? If you wanted to use it like this I would either define an object to be the <String, System.Object> and inserting that as the value and just leave the key as the number.
Or making a list of objects where the object is the <String, System.Object>
#ILiveForVR makes me think about this.thanks.
I solved it, but I'm not sure if the solution is best.
I do it like this:
var list = List.<System.Object>;
for(var i=0;i<list.Count;i++){
var data = list[i] as Dictionary<String, System.Object>;
}