String jsonString = [{"color":"#000000","quantity":"100","price":"999","attribute":{"id":1,"name":"SIZE"}},{"color":"#cd7d96","quantity":"40","price":"555","attribute":{"id":2,"name":"FABRIC"}},{"color":"#66cccc","quantity":"500","price":"1000","attribute":{"id":1,"name":"SIZE"}}]
How can I group by and archive results as below
[{"attribute_id":1, "values":["#000000","#66cccc"]},{"attribute_id":2, "values":["#cd7d96"]}]
import 'dart:convert';
const raw =
'''
[{"color":"#000000","quantity":"100","price":"999","attribute":{"id":1,"name":"Iphone 12"}},{"color":"#cd7d96","quantity":"40","price":"555","attribute":{"id":2,"name":"SAMSUNG"}},{"color":"#66cccc","quantity":"500","price":"1000","attribute":{"id":1,"name":"OPPO"}}]
''';
typedef JMap = Map<String, dynamic>;
typedef LJMap = List<JMap>;
void groupById() {
final data = (jsonDecode(raw) as List).cast<JMap>();
var result = <JMap>[];
data.map<int>((m) => m['attribute']['id']).toSet().forEach((e) {
result.add({
'attribute_id': e,
'values': data.where((m) => m['attribute']['id'] == e).map((m) => m['color']).toList(),
});
});
print(result);
}
void main(List<String> args) {
groupById();
}
Output:
[{attribute_id: 1, values: [#000000, #66cccc]}, {attribute_id: 2, values: [#cd7d96]}]
Related
I was wondering if someone could help? I'm trying to load a file with json content, decode it, convert to a model/object add another element.
The way I'm trying to do this is as follows:
Flow 1: Check file exists = true -> return file object -> decode string to json -> convert to model/object -> add element -> back to json -> to string -> save file.
Flow 2: Check file exists = false -> create file -> add a json template -> return file object -> decode string to json -> convert to model/object -> add element -> back to json -> to string -> save file.
This is working on the first run (flow 1), it'll create the file, add the template then add the first new element. However, when I run it a second time (flow 2), I always get an throwback.
As we speak with the code below, the error is:
E/flutter (13140): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'Map<dynamic, dynamic>'
E/flutter (13140): #0 FileController.writeSingleResponseToFile (package:reefcommander/controllers/FileController.dart:33:39)
E/flutter (13140): <asynchronous suspension>
E/flutter (13140):
This is the code I'm using.
FileController.dart
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:intl/intl.dart';
import 'package:reefcommander/models/ReadingsData.dart';
import 'package:reefcommander/models/SingleDataReqResponse.dart';
import 'dart:convert';
class FileController {
static String date = DateFormat("dd-MM-yyyy").format(DateTime.now());
static String template =
'{"name": "_NAME_", "friendlyName": "_FNAME_", "results": []}';
static final Map<String, String> nameDefenitions = {
'ec': 'EC',
'ph': 'pH',
'atoDayRate': 'Evap Rate',
'sumpTemp': 'Temp (sump)',
'tankTemp': 'Temp (tank)'
};
static Future<File> checkFileExists(String type) async {
readFile(type);
final Directory? directory = Platform.isAndroid
? await getExternalStorageDirectory() //FOR ANDROID
: await getApplicationSupportDirectory();
final String filename = '${directory!.path}/${date}_$type.json';
final File file = File(filename);
return file;
}
static writeSingleResponseToFile(SingleDataReqResponse resp) async {
final File file = await checkFileExists(resp.name.toString());
var r = Map<String, dynamic>.from(jsonDecode(await file.readAsString()));
print(r.runtimeType);
ReadingsData existingdata = ReadingsData.fromJson(r[0]);
//ReadingsData existingdata =
// r.map<ReadingsData>((json) => ReadingsData.fromJson(json));
print(existingdata);
existingdata.results!.add(Results(stamp: resp.stamp, value: resp.value));
print('DATA: ${existingdata.toJson().toString()}');
file.writeAsString(jsonEncode(existingdata.toJson().toString()));
}
static Future<void> deleteFile(String type) async {
try {
final Directory? directory = Platform.isAndroid
? await getExternalStorageDirectory() //FOR ANDROID
: await getApplicationSupportDirectory();
final String filename = '${directory!.path}/${date}_$type.json';
final File file = File(filename);
if (file.existsSync()) {
await file.delete();
} else {}
} catch (e) {
// Error in getting access to the file.
}
}
static Future<String> readFile(String type) async {
String text = '';
try {
final Directory? directory = Platform.isAndroid
? await getExternalStorageDirectory() //FOR ANDROID
: await getApplicationSupportDirectory();
final String filename = '${directory!.path}/${date}_$type.json';
final File file = File(filename);
if (file.existsSync()) {
text = await file.readAsString();
} else {
file.create(recursive: true);
String tempbase = template;
String write = tempbase
.replaceAll('_NAME_', type.toString())
.replaceAll('_FNAME_', nameDefenitions[type]!);
await file.writeAsString(write);
text = await file.readAsString();
}
} catch (e) {
print("Read error");
}
return text;
}
}
ReadingsData.dart
import 'dart:convert';
class ReadingsData {
String? name;
String? friendlyName;
List<Results>? results;
ReadingsData(
{required this.name, required this.friendlyName, required this.results});
ReadingsData.fromJson(Map<String, dynamic> json) {
name = json['name'];
friendlyName = json['friendlyName'];
if (json['results'] != null) {
results = <Results>[];
json['results'].forEach((v) {
results!.add(Results.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['name'] = name;
data['friendlyName'] = friendlyName;
if (results != null) {
data['results'] = results!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Results {
String? stamp;
String? value;
Results({required this.stamp, required this.value});
Results.fromJson(Map<String, dynamic> json) {
stamp = json['stamp'];
value = json['value'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['stamp'] = stamp;
data['value'] = value;
return data;
}
}
Test code
FileController.writeSingleResponseToFile(
SingleDataReqResponse(name: "test", stamp: "10:22:00", value: "2222"));
For anyone else in my situation, I've resolved it. Solution below.
static writeSingleResponseToFile(SingleDataReqResponse resp) async {
final File file = await checkFileExists(resp.name.toString());
ReadingsData existingdata =
ReadingsData.fromJson(jsonDecode(await file.readAsString()));
existingdata.results!.add(Results(stamp: resp.stamp, value: resp.value));
file.writeAsString(jsonEncode(existingdata.toJson()));
}
I am beginner in flutter. Please help me get and set below json data into model in flutter. I am using POST method.
'''
{
"success": 1,
"data": {
"user_id": 2,
"email": "ajay.singhal#ollosoft1.com",
"phone": "9414905280",
"password": "1436a615e62482ba4f075c1d4a4fd94b",
"account_status": "Active",
"date_of_birth": "1953-09-07T00:00:00.000Z",
"address": "Jaipur Rajasthan",
"profile_url": "http://18.217.236.99:4200/assets/profile_img/2/RBI-keeps-policy-rate-unchanged-1.jpg",
"first_name": "Ajay",
"last_name": "singhal"
}
}
'''
Below is my Model class named UserInfoModel
import 'UserInfoDataModel.dart';
class UserInfoModel {
final int success;
final UserInfoDataModel data;
UserInfoModel(this.success, this.data);
factory UserInfoModel.fromJson(dynamic json) {
if (json['data'] != null) {
var tagObjsJson = json['data'];
UserInfoDataModel _tags =
tagObjsJson.map((tagJson) => UserInfoDataModel.fromJson(tagJson));
return UserInfoModel(json['success'] as int, _tags);
}
}
#override
String toString() {
return '{${this.success}, ${this.data}}';
}
}
Below is submodel name is UserInfoDataModel
import 'package:flutter/material.dart';
class UserInfoDataModel {
int user_id;
String email;
String phone;
String password;
String account_status;
String date_of_birth;
String address;
String profile_url;
String first_name;
String last_name;
UserInfoDataModel(
{this.user_id,
this.email,
this.phone,
this.password,
this.account_status,
this.date_of_birth,
this.address,
this.profile_url,
this.first_name,
this.last_name});
factory UserInfoDataModel.fromJson(Map<String, dynamic> json) {
return UserInfoDataModel(
user_id: json['user_id'] as int,
email: json['email'],
phone: json['phone'],
password: json['password'],
account_status: json['account_status'],
date_of_birth: json['date_of_birth'],
address: json['address'],
profile_url: json['profile_url'],
first_name: json['first_name'],
last_name: json['last_name'],
);
}
}
My APi Call is below Using POST Method
I am successfully getting response, but unable to set in model
UserInfoModel _userInfoModel;
UserInfoDataModel _userInfoDataModel;
String url = BaseURLHeaders().getBaseURl() + "userInfo";
Map headers = BaseURLHeaders().getHeader();
#override
void initState() {
// TODO: implement initState
super.initState();
getData();
}
Future<UserInfoModel> getData() async {
String user_id = "1";
var mapData = new Map<String, dynamic>();
mapData['user_id'] = user_id;
// mapData['first_name'] = firstName;
var response = await http.post(
url,
headers: headers,
body: mapData,
);
setState(() {
print("userInfoDetails: ${response.body}");
print("urlTop: ${url}");
print("headersTop: ${headers}");
print("responseCode: ${response.statusCode}");
});
if (response.statusCode == 200) {
var res = json.decode(response.body);
_userInfoModel = UserInfoModel.fromJson(res);
if (_userInfoModel.success == 1) {
var data = res["data"];
setState(() {
print("responseBody: ${res}");
print("userInfoSuccess: ${_userInfoModel.success}");
print("dataVaalue: ${data["email"]}");
print("urlBelow: ${url}");
print("headersBelow: ${headers}");
});
}
}
}
UserInfoDataModel _tags =
tagObjsJson.map((tagJson) => UserInfoDataModel.fromJson(tagJson));
here you are actually treated tagObjsJson as a list. but it is a JsonObject so there you don't want the map function.
you can access the object as
UserInfoDataModel _tags =UserInfoDataModel.fromJson(tagJson);
You can use json_serializer in flutter. See flutter docs.
If you use IntelliJ IDEA, you can use DartToJson package. It generates automatically for you and you can use fromJson and toJson method.
I want to fetch dat form some API and parse its data to model.
MyModel:
class SetupIdeaModel {
String id;
String userId;
String typeIdea = "Implemented Idea";
String category; //Or Industry
String experienceYear;
String experienceMonth;
String ideaHeadline;
String ideaText;
Map timeline = {
"timelineType": "date",
"details": null,
};
List documents = [];
Map uploadVideo;
String location;
String estimatedPeople;
Map whitePaper;
bool needServiceProvider = false;
bool needInvestor = true;
}
}
and I fetch data from the API with the getIdeaList method:
getIdeaList method
Future getIdeaList(String token) async {
Response response = await APIRequest().get(
myUrl: "$baseUrl/innovator/idea/list",
token: token,
);
//Parsing ideaList to SetupIdeaModel
ideas = List();
try {
(response.data as List).forEach((element) {
SetupIdeaModel idea = new SetupIdeaModel();
var months = int.parse(element["industryExperienceInMonth"]);
var year = (months / 12).floor();
var remainderMonths = months % 12;
print("$year year and $remainderMonths months");
idea.id = element["_id"];
idea.userId = element["userId"];
idea.typeIdea = element["ideaType"];
idea.category = element["industry"];
idea.experienceYear = year.toString();
idea.experienceMonth = remainderMonths.toString();
idea.ideaHeadline = element["headline"];
idea.ideaText = element["idea"];
idea.estimatedPeople = element["estimatedPeople"].toString();
print("Documents ${element["uploadDocuments"]}");
idea.location = element["targetAudience"];
idea.documents = element["uploadDocuments"];
// idea.timeline = element["timeline"];
// idea.uploadVideo = element["uploadVideo"];
ideas.add(idea);
});
} catch (e) {
print("Error: $e");
}
print("ideas $ideas");
notifyListeners();
}
Everything is OK but When I add one of these line:
idea.documents = element["uploadDocuments"];
idea.timeline = element["timeline"];
idea.uploadVideo = element["uploadVideo"];
I have got the error.
The data comes for the API is like this:
[
{
"industryExperienceInMonth":30,
"estimatedPeople":200,
"needServiceProvider":true,
"needInvestor":true,
"_id":5fcc681fc5b4260011810112,
"userId":5fb6650eacc60d0011910a9b,
"ideaType":"Implemented Idea",
"industry":"Technalogy",
"headline":"IDea headline",
"idea":"This is aobut your idea",
"timeline":{
"timelineType":"date",
"details":{
"date":Dec 6,
2020
}
},
"uploadDocuments":[
{
"_id":5fcc6804c5b4260011810110,
"uriPath":"https"://webfume-onionai.s3.amazonaws.com/guest/public/document/741333-beats_by_dre-wallpaper-1366x768.jpg
}
],
"uploadVideo":{
"_id":5fcc681ac5b4260011810111,
"uriPath":"https"://webfume-onionai.s3.amazonaws.com/guest/public/video/588700-beats_by_dre-wallpaper-1366x768.jpg
},
"targetAudience":"heart",
"__v":0
}
]
I'm using Dio package.
The documents in the model is a list and the uploadDocuments the come form API is a list too. But Why I got this error.
Your JSON data has some syntax errors that's why it's not working. All the UIDs and URLs should be in string format and you should Serializing JSON inside model classes. see also
I have fix some error in your code and did some improvement :
Future getIdeaList(String token) async {
List<SetupIdeaModel> setupIdeaModel = List();
try {
Response response = await APIRequest().get(
myUrl: "$baseUrl/innovator/idea/list",
token: token,
);
if (response.statusCode == 200) {
List<SetupIdeaModel> apiData = (json.decode(utf8.decode(response.data)) as List)
.map((data) => new SetupIdeaModel.fromJson(data))
.toList();
setupIdeaModel.addAll(apiData);
}
} catch (e) {
print("Error: $e");
}
}
This is the model class :
class SetupIdeaModel {
int industryExperienceInMonth;
int estimatedPeople;
bool needServiceProvider;
bool needInvestor;
String sId;
String userId;
String ideaType;
String industry;
String headline;
String idea;
Timeline timeline;
List<UploadDocuments> uploadDocuments;
UploadDocuments uploadVideo;
String targetAudience;
int iV;
SetupIdeaModel(
{this.industryExperienceInMonth,
this.estimatedPeople,
this.needServiceProvider,
this.needInvestor,
this.sId,
this.userId,
this.ideaType,
this.industry,
this.headline,
this.idea,
this.timeline,
this.uploadDocuments,
this.uploadVideo,
this.targetAudience,
this.iV});
SetupIdeaModel.fromJson(Map<String, dynamic> json) {
industryExperienceInMonth = json['industryExperienceInMonth'];
estimatedPeople = json['estimatedPeople'];
needServiceProvider = json['needServiceProvider'];
needInvestor = json['needInvestor'];
sId = json['_id'];
userId = json['userId'];
ideaType = json['ideaType'];
industry = json['industry'];
headline = json['headline'];
idea = json['idea'];
timeline = json['timeline'] != null
? new Timeline.fromJson(json['timeline'])
: null;
if (json['uploadDocuments'] != null) {
uploadDocuments = new List<UploadDocuments>();
json['uploadDocuments'].forEach((v) {
uploadDocuments.add(new UploadDocuments.fromJson(v));
});
}
uploadVideo = json['uploadVideo'] != null
? new UploadDocuments.fromJson(json['uploadVideo'])
: null;
targetAudience = json['targetAudience'];
iV = json['__v'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['industryExperienceInMonth'] = this.industryExperienceInMonth;
data['estimatedPeople'] = this.estimatedPeople;
data['needServiceProvider'] = this.needServiceProvider;
data['needInvestor'] = this.needInvestor;
data['_id'] = this.sId;
data['userId'] = this.userId;
data['ideaType'] = this.ideaType;
data['industry'] = this.industry;
data['headline'] = this.headline;
data['idea'] = this.idea;
if (this.timeline != null) {
data['timeline'] = this.timeline.toJson();
}
if (this.uploadDocuments != null) {
data['uploadDocuments'] =
this.uploadDocuments.map((v) => v.toJson()).toList();
}
if (this.uploadVideo != null) {
data['uploadVideo'] = this.uploadVideo.toJson();
}
data['targetAudience'] = this.targetAudience;
data['__v'] = this.iV;
return data;
}
}
class Timeline {
String timelineType;
Details details;
Timeline({this.timelineType, this.details});
Timeline.fromJson(Map<String, dynamic> json) {
timelineType = json['timelineType'];
details =
json['details'] != null ? new Details.fromJson(json['details']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['timelineType'] = this.timelineType;
if (this.details != null) {
data['details'] = this.details.toJson();
}
return data;
}
}
class Details {
String date;
Details({this.date});
Details.fromJson(Map<String, dynamic> json) {
date = json['date'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['date'] = this.date;
return data;
}
}
class UploadDocuments {
String sId;
String uriPath;
UploadDocuments({this.sId, this.uriPath});
UploadDocuments.fromJson(Map<String, dynamic> json) {
sId = json['_id'];
uriPath = json['uriPath'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['_id'] = this.sId;
data['uriPath'] = this.uriPath;
return data;
}
}
I want to convert a string to multi-level list, but I cannot find a efficient way to do.
From String:
[[1,2,3],[1,2]]
To List:
List< List < int>>
Try this as a funtion
List<List<int>> convert(String val){
List<List<int>> list = [];
jsonDecode(val).forEach((mainList) {
List<int> subList = [];
mainList.forEach((sList) {
subList.add(sList);
});
list.add(subList);
});
return list;
}
Also import dart:convert;
String str = '[[1,2,3],[1,2]]';
List<List<int>> list=[];
for(String s in str.split('],[')){
List<int> l = [];
String formattedString = s.replaceAll('[','').replaceAll(']','');
for(String innerS in formattedString.split(',')){
l.add(int.parse(innerS));
print(l);
}
list.add(l);
}
Output: [[1, 2, 3], [1, 2]]
Shorter version:
import 'dart:convert';
void main() {
var jsonMap = "[[1,2,3],[1,2]]";
List<List<int>> items = (jsonDecode(jsonMap) as List).map((lst) =>
(lst as List).map((i) => (i as int)).toList()).toList();
print(items);
}
Is it possible to deserialize a json with dynamic key but structured values into Map in flutter dart.
I am having a json like
{
"data" : {
"apple":{"qty":5, "price":100},
"orange":{"qty":2, "price":40},
}
}
And I want this to deserialize in flutter/dart to a model class below
class Data {
Map<String, Item> itemMap;
factory Data.fromJson(Map<String,dynamic> json) {
itemMap : json["data"]; //How to parse.
}
}
class Item {
int qty;
int price;
}
I have read through a medium blog and even this also not covering the Map part.
You need to do something like this:
//...
Future<List<ItemModel>> fetchFood() async {
List<ItemModel> foodItemsList = [];
// Get json response and parse it as a Map<String, dynamic>
final response = {
"data" : {
"apple":{"qty":5, "price":100},
"orange":{"qty":2, "price":40},
}
};
// with your real get request use this:
// final parsedJson = json.decode(response.body)['data'];
// Parsed Json have what's inside data, in case of real request look for the line above this.
final parsedJson = response['data'];
// Iterate over all fruits and create Item object from each,
// then push to a list of Item's objects to return it.
parsedJson.forEach((k,v) => foodItemsList.add(ItemModel.fromJson(v)));
return foodItemsList;
}
// Item model
class ItemModel {
int qty;
int price;
ItemModel.fromJson(Map<String,dynamic> parsedJson)
: qty = parsedJson['qty'],
price = parsedJson['price'];
}
// Then call it
main() async {
List<ItemModel> foodItemsList = await fetchFood();
//..
}
If you need the fruit name as part of the object:
//...
Future<List<ItemModel>> fetchFood() async {
List<ItemModel> foodItemsList = [];
// Get json response and parse it as a Map<String, dynamic>
final response = {
"data" : {
"apple":{"qty":5, "price":100},
"orange":{"qty":2, "price":40},
}
};
// with your real get request use this:
// final parsedJson = json.decode(response.body)['data'];
// Parsed Json have what's inside data, in case of real request look for the line above this.
final parsedJson = response['data'];
// Iterate over all fruits and create Item object from each,
// then push to a list of Item's objects to return it.
parsedJson.forEach((fruitName, fruitDetails)
=> foodItemsList.add(
ItemModel.fromJson(fruitName, fruitDetails)
)
);
return foodItemsList;
}
// Item model
class ItemModel {
String name;
int qty;
int price;
ItemModel.fromJson(String fruitName, Map<String,dynamic> parsedJson)
: name = fruitName,
qty = parsedJson['qty'],
price = parsedJson['price'];
}
// Then call it
main() async {
List<ItemModel> foodItemsList = await fetchFood();
print(foodItemsList[1].name); //orange
//..
}
I have a similar JSON with a few changes:
{
"sub_item": {
"491": ["92837|1.3|Pistachio|right", "92838|2.5|Hazelnut|left"],
"427": ["92839|7.05|Almonds|", "92840|5.12|Walnuts|"],
"396": ["92841|15|Saffron|"],
"275": ["92842|45|Caviar|"]
}
}
The keys of sub_item map (491, 427, 396, 275, and...) are dynamic(as a label not as a type) and will change per order. For example, it will be 376, 325, 493... in another order.
I want to shows both keys and values on my Flutter app and do not know how to fetch these data and show them separately. Something like this:
491:
£1.30 Pistachio
£2.50 Hazelnut
427:
£7.05 Almonds
£5.12 Walnuts
396:
£15.00 Saffron
275:
£45.00 Caviar
I used this code and it worked for me somehow but it shows only the first item of the lists. for example, it shows only Pistachio for 491 not Hazelnut and the same it shows only Almonds for 427 not Walnuts:
Future<List<ItemModel>> fetchFood() async {
List<ItemModel> foodItemsList = [];
final response = {
"sub_item": {
"491": ["92837|1.3|Pistachio|right", "92838|2.5|Hazelnut|left"],
"427": ["92839|7.05|Almonds|", "92840|5.12|Walnuts|"],
"396": ["92841|15|Saffron|"],
"275": ["92842|45|Caviar|"]
}
};
final parsedJson = response['sub_item'];
parsedJson.forEach((fruitName, fruitDetails) =>
foodItemsList.add(ItemModel.fromJson(fruitName, fruitDetails)));
return foodItemsList;
}
// Item model
class ItemModel {
String id;
String details;
ItemModel.fromJson(String subItemID, List<dynamic> subItemDetails)
: id = subItemID,
details = subItemDetails[0];
}
// Then call it
mainTest() async {
List<ItemModel> foodItemsList = await fetchFood();
for (var i = 0, j = 0;
i < foodItemsList.length;
j < foodItemsList[i].details.length, i++, j++) {
print(foodItemsList[i].id);
print(foodItemsList[j].details.split('|')[2]);
}
}
The console result:
flutter: 491
flutter: Pistachio
flutter: 427
flutter: Almonds
flutter: 396
flutter: Saffron
flutter: 275
flutter: Caviar
I found a way to achieve it. We can convert the Map from one type to another.
class Data {
Map<String, Item> itemMap;
factory Data.fromJson(Map<String,dynamic> json) {
itemMap : getMapDataFrom(json["data"]); //How to parse.
}
static Map<String, Item> getFruitItemMap(Map<String, dynamic> map) {
final Map<String, Item> fruitItemMap = HashMap();
map.forEach((name, value) {
bitItemLites[name] = Item.fromJson(value, name);
});
return bitItemLites;
}
}
class Item {
int qty;
int price;
factory Item.fromJson(Map<String,dynamic> json) {
return Item(json['qty'], json['price']);
}
}