I am basically from JS background and now trying my hands on flutter framework.
I am stuck in formatting my data I received from API.
Data Received an array of objects
[
{
"id": 1,
"name": "name1",
"type": "Both",
"count": 4
},
{
"id": 2,
"name": "name2",
"type": "Both",
"count": 6
},
{
"id": 3,
"name": "name1",
"type": "Both",
"count": 2
},
{
"id": 4,
"name": "name3",
"type": "Both",
"count": 8
},
......
]
My Requirement is I will have to group the data based on the name
{
name1: [
{
"id": 1, "name":"name1", "type": "Both", "count": 4
},
{
"id": 3, "name":"name1", "type": "Both", "count": 2
}
],
name2: [
{
"id": 2, "name":"name2", "type": "Both", "count": 6
}
],
.....
}
In dart, I have managed to do that grouping using groupBy from collections.dart package.
The problem is I cannot loop through the grouped data. I need to access the count for some manipulation for each grouped name.
Below is the code snipped which I tried
Map data;
List partySnapData;
Map newMap;
Future _getTopParties() async {
final response =await http.get(API_URL + '/getPartySnapShot');
data =json.decode(response.body);
partySnapData = data['resultObj'];
setState(() {
newMap = groupBy(partySnapData, (obj) => obj['party_name']);
for(var v in newMap.values) {
print(v);
}
});
}
The print(v) actually gave me the value mapped for the map E.G
[
{ "id": 1, "name":"name1", "type": "Both", "count": 4 },
{ "id": 3, "name":"name1", "type": "Both", "count": 2 }
],
.....,
......
Now, how do I loop or iterate through the array, here the v, so that i can access the elements inside?
I found a solution to this. I am posting that, incase it helps someone.
I wanted to loop through the v to generate objects.
newMap = groupBy(partySnapData, (obj) => obj['party_name']);
for(var v in newMap.values) {
print(v);
//below is the solution
v.asMap().forEach((i, value) {
print('index=$i, value=$value');
}
}
Ignoring your specific case but answering the question in case others come across this question like I did while searching for How to iterate through map values in dart / flutter.
There is a simpler and a better approach.
Here's the best approach (because this way you can break the for loop after finding the right entry and doing what you had to do to avoid unnecessary iterations).
for (MapEntry<type, type> item in myMap.entries) {
//Here each item has a key and a value proterties.
//Don't forget to use break; to end the loop when you are done and avoid unnecessary iterations.
}
And here is the easier:
myMap.forEach((key, value) {
//Here you have key and value for each item in your map but you can't break the loop
//to avoid unnecessary iterations.
//This approach is only useful when you need to perform changes in all Map items.
});
UPDATED
List<Map> list = [
{
"id": 1,
"name": "name1",
"type": "Both",
"count": 4
},
{
"id": 2,
"name": "name2",
"type": "Both",
"count": 6
},
{
"id": 3,
"name": "name1",
"type": "Both",
"count": 2
},
{
"id": 4,
"name": "name3",
"type": "Both",
"count": 8
}];
Map sorted={};
#override
void initState(){
super.initState();
for(Map m in list){
if(sorted[m['name'].toString()]==null)
sorted[m['name'].toString()]=[];
sorted[m['name'].toString()].add(m);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body:Container(
padding:EdgeInsets.all(20),
color:Colors.white,
alignment:Alignment.center,
child:Column(
mainAxisSize:MainAxisSize.min,
children: <Widget>[
Text('Original\n $list',
style:TextStyle(color:Colors.black)),
SizedBox(height:15),
Text('Sorted\n $sorted',
style:TextStyle(color:Colors.black)),
//EDIT
SizedBox(height:15),
ListView(
shrinkWrap:true,
children: sorted.entries.map<Widget>((value){
return Column(
mainAxisSize:MainAxisSize.min,
crossAxisAlignment:CrossAxisAlignment.start,
children:[
Text(value.key.toString(),style:TextStyle(color:Colors.black,
fontWeight:FontWeight.bold)),
Column(
mainAxisSize:MainAxisSize.min,
children:value.value.map<Widget>((subValue){
return Text(subValue['count'].toString(),style:TextStyle(color:Colors.black));
}).toList(),
),
]
);
}).toList(),
)
],
)
)
);
}
Related
I have this payload that I need to send to a server
"members": [
{
"names": "ben",
"date-of-birth": "1978-01-01",
"gender": "Male",
"surname": "surname",
"role": "Partner",
"total-cut": "100.00"
}
],
Only thing is at times there are no members, and following this am not supposed to send the array at all, it should just be nothing at all, no members.
For clarification, this is an example only, think there is a members object, like the above, schools object, courses object, only at times some of this come up empty and consequently I should omit the empty object entirely.
For example, in the below, if there are no members,,
{
"members": [
{
"names": "ben",
"date-of-birth": "1978-01-01",
"gender": "Male",
"surname": "surname",
"role": "Partner",
"total-cut": "100.00"
}
],
"courses": [
{
"name": "ben",
"number": "32",
"teacher": "Russ",
"cut": "10.00"
}
],
}
how can i create a conditional that omits the members and leaves courses only
{
"courses": [
{
"name": "ben",
"number": "32",
"teacher": "Russ",
"cut": "10.00"
}
],
}
For context this is a post request
I don't know if this has been solved or not yet (I hope yes :P). But this is a practical approach for reference in case others do run into a similar issue.
Problem
Before, here is a problem rephrasing just to make sure we are on the same line. If you have members, add them to the map otherwise no. In both these conditions the map should look like this:
// With members
{
"members": [
{
"names": "member_name",
//...
}
],
"courses": [
{
"name": "course_name",
//...
}
],
}
// Without members
{
"courses": [
{
"name": "course_name",
//...
}
],
}
Solution
In my opinion, the best way to handle this is to declare an empty Map() and conditionally add entries to it as fellows:
Map<String, dynamic> buildMyMap(){
final buffer = <String, dynamic>{};
if(members.isNotEmpty){
// Option 1
buffer.addEntries(MapEntry("members", members));
// Option 2
buffer["members"] = members;
}else{
// (Optional) In case you want to delete pre-existing members
buffer.remove("members");
}
if(courses.isNotEmpty){
// Option 1
buffer.addEntries(MapEntry("courses", courses));
// Option 2
buffer["courses"] = courses;
}else{
// (Optional) in case you want to remove pre-existing courses!
buffer.remove('courses');
}
return buffer;
}
You should declare the parameter members to be optional in your API, then you have no need to send this parameter.
you can do the following
final List members = [];
final List courses = [];
final map = {
if (members.isNotEmpty)
'members': [
for (final member in members)
{
"names": "ben",
"date-of-birth": "1978-01-01",
"gender": "Male",
"surname": "surname",
"role": "Partner",
"total-cut": "100.00"
}
],
if (courses.isNotEmpty)
'courses': [
for (final course in courses)
{
"name": "ben",
"number": "32",
"teacher": "Russ",
"cut": "10.00"
}
]
};
you can use if statement inside a map or a list in flutter,
also, if you want to multiple fields if a condition is met
final map2 = {
if(true)...{
'name': 'name',
'age': '12'
} else ...{
'name': 'NO NAME',
'age': 'NO AGE'
}
};
Given the following map:
"user":
{
"userid":0,
},
"appData":{
"title":"Test",
"pages":1,
"posts":[
{
"postid":27979530,
"text":Test,
},
{
"postid":7732445,
"text":Test123,
},
{
"postid":9463254,
"text":Test568,
},
]
}
Given that map I want to try to find the entry for postid 7732445 so I can return the text value of Test123
What is the best way of doing something like that?
Given that
final Map<String, dynamic> json = {
"user": {
"userid": 0,
},
"appData": {
"title": "Test",
"pages": 1,
"posts": [
{
"postid": 27979530,
"text": "Test",
},
{
"postid": 7732445,
"text": "Test123",
},
{
"postid": 9463254,
"text": "Test568",
},
]
}
};
you could do this search by doing
json["appData"]["posts"]
.firstWhere(
(item) => item["postid"] == 7732445,
orElse: () => <String, Object>{},
)["text"]
Because of the orElse, this will return null if not found.
Let's say I have a column with this jsonb data :
{
"indicators": [
{
"year": 2019,
"indicatorsByYear": [
{
"value": 3120,
"code": "Nb_h"
},
{
"value": 18,
"code": "S_ppa"
},
{
"value": 95,
"code": "T_occ"
}
]
},
{
"year": 2020,
"indicatorsByYear": [
{
"value": 300,
"code": "Nb_h"
},
{
"value": 18,
"code": "S_ppa"
},
{
"value": 55,
"code": "T_occ"
}
]
}
],
"dataProvidedByUser": false
}
The idea is to migrate this column to a simplified object like this :
{
"indicatorsByYear": {
"2019": [
{
"value": 3120,
"code": "Nb_h"
},
{
"value": 18,
"code": "S_ppa"
},
{
"value": 95,
"code": "T_occ"
}
],
"2020": [
{
"value": 300,
"code": "Nb_h"
},
{
"value": 18,
"code": "S_ppa"
},
{
"value": 55,
"code": "T_occ"
}
]
},
"dataProvidedByUser": false
}
How can I transform the indicators array to map object with year as key and indicatorsByYear as value.
For info, the maximum number of years that I can have is 11 years (from 2010 to 2020), some columns have all the years others only some.
My attempts with something like that without success
update site
SET data = data
|| jsonb_build_object('indicatorsByYear',
jsonb_build_object(
data -> 'indicators' ->> 'year',
data -> 'indicators' ->> 'indicatorsByYear'
))
Any help would be very much appreciated! Thanks in advance.
data -> 'indicators' is an array, whose elements you need to consider individually and then aggregate back together into an object. You can use jsonb_array_elements and jsonb_object_agg respectively for this.
Also, you'll want to remove the old indicators key from the data column.
UPDATE site
SET data = jsonb_set(
data - 'indicators',
'{indicatorsByYear}',
(
SELECT jsonb_object_agg(el ->> 'year', el -> 'indicatorsByYear')
FROM jsonb_array_elements(data -> 'indicators') el
)
);
I have a map, with multiple layers, some of the layers have an events field which may contain 0 or more event listings inside of it.
Some of events are nested deeper into the map, while others are closer to the top layer.
Here is what the graphql query result looks like:
{
"data": {
"users": [
{
"id": 16,
"friends": [
{
"senderId": 16,
"receiverId": 17,
"userByReceiverid": {
"id": 17,
"events": [],
"friends": [
{
"receiverId": 14,
"userByReceiverid": {
"id": 14,
"events": [
{
"id": 3,
"photoUrl": "none",
"name": "hello",
"date": "1982-06-27",
"startTime": "01:00:00+00",
"endTime": "02:00:00+00",
"fee": "$2.00",
"maxNumber": 10,
"ageRestriction": "none",
"about": "amazing",
"allowShare": false,
"private": false,
"timestamp": "2021-06-26T17:57:13.224383+00:00",
"senderId": 14
}
]
}
},
{
"receiverId": 20,
"userByReceiverid": {
"id": 20,
"events": []
}
}
]
}
}
],
"friendsByReceiverid": [
{
"senderId": 20,
"receiverId": 16,
"user": {
"id": 20,
"events": [],
"friendsByReceiverid": [
{
"receiverId": 20,
"user": {
"id": 14,
"events": [
{
"id": 3,
"photoUrl": "none",
"name": "hello",
"date": "1982-06-27",
"startTime": "01:00:00+00",
"endTime": "02:00:00+00",
"fee": "$2.00",
"maxNumber": 10,
"ageRestriction": "none",
"about": "amazing",
"allowShare": false,
"private": false,
"timestamp": "2021-06-26T17:57:13.224383+00:00",
"senderId": 14
}
]
}
},
{
"receiverId": 20,
"user": {
"id": 17,
"events": []
}
}
]
}
}
]
}
]
}
}
I want to search the Map and make a list that contains all the events that are unique, so no duplicates if possible.
How would I go about pulling out only the events field from a map at any given point?
Essentially what you need is a function (visitObject) that goes through each key of the a Map and recursively calls itself till all properties have been checked.
The function should also check for the possible types it can operate on and handle the data so you can call the visitObject function with the right arguments.
I believe the right data structure here would be a Set. In dart as Set is defined as A collection of objects in which each object can occur only once.
However Set a set falls back to the dart method of equality which is the == operator, so you would either need to use a calls for Events or use a package like BuiltValue which will generate the == operator for your value types.
Here is an example that can help you get started, I have left equality checking for you to determine what best and how you want to apply it.
final Set<Map<String, dynamic>> items = {};
void main() {
visitObject(data);
}
void visitObject(object) {
if (object is List) {
for(dynamic item in object) {
visitObject(item);
}
} else if (object is Map) {
if (object.containsKey('events')) {
var _events = object['events'];
if (_events is List && _events.isNotEmpty) {
_events.forEach((e) {
if (!items.contains(e)) {
items.add(e);
}
});
}
}
for (dynamic item in object.values) {
visitObject(item);
}
}
}
Additional Reading for equality:
==Operator
hashCode
BuiltValue
I'm trying to get the GitHub data using Talend big data. The thing is, i have multiple URLs,because used each URL to take some values & stored into single mongoDB. The below order only i'm going to try & get the informations,
https://api.github.com/users/sample/repos
https://api.github.com/repos/sample/awesome-ciandcd/commits
https://api.github.com/repos/sample/awesome-ciandcd/contributors
Each URLs are giving the single JSONArray with multiple data format.Please give some suggestion to do this. I've already tried with sub-jobs component. But not get clear job.
My Output Should be like,
{
"gitname": "sample",
"gitType" : "User",
"password": "password",
"repoCount": 3,
"repositoryDetails": [
{
"repoName": "MergeCheckRepository",
"fileCount": 10,
"branchCount": 6,
"releaseCount": 2,
"commitsCount": 10,
"contributorsCount": 3,
"totalPulls": 1,
"mergeCount": 1,
"totalIssues": 12,
"closedIssueCount": 3,
"watchersCount": 1,
"stargazersCount": 4,
"contributorsDetails": [
{
"login": "sample",
"avatarURL": "https://avatars2.githubusercontent.com/u/30261572?v=4",
"contributions": 3
}
],
"commitDetails": [
{
"name": "sample",
"email": "sampletest#test.com",
"date": "2017-07-20T09:09:09Z"
}
]
},
{
"repoName": "Dashboard",
"filecount": 19,
"branchCount": 4,
"releasecount": 2,
"commitsCount": 5,
"contributorsCount": 3,
"totalPulls": 1,
"totalIssues": 2,
"closedIssueCount": 3,
"watchersCount": 1,
"stargazersCount": 4,
"contributorsDetails": [
{
"login": "sample",
"avatarURL": "https://avatars2.githubusercontent.com/u/30261572?v=4",
"contributions": 3
},
{
"login": "Dashboard",
"avatarURL": "https://avatars2.githubusercontent.com/u/30261572?v=4",
"contributions": 3
}
],
"commitDetails": [
{
"name": "sample",
"email": "sampletest#test.com",
"date": "2017-07-14T09:09:09Z"
},
{
"name": "Dashboard",
"email": "prakash.thangasamy#test.com",
"date": "2017-07-19T09:09:09Z"
},
{
"name": "testrepo",
"email": "test.dashboard#test.com",
"date": "2017-07-20T09:09:09Z"
}
]
}
]
}
How to achieve this one with sub-job? Is there any other way to do this?