Display list of map without duplication/repetition - Dart - dart

I'm trying to display/print list of map without duplicate element. For example:
List userList = [
{'name': 'john', 'user_id': '251'},
{'name': 'will', 'user_id': '255'},
{'name': 'jack', 'user_id': '251'} // duplicate
];
this is what I'm trying to output/print
List userList = [
{'name': 'john', 'user_id': '251'},
{'name': 'will', 'user_id': '255'},
];
some of you may suggest to use toSet method but that is valid only for list (not list of map)

This is one of the reasons why we should not use maps in Dart as data structures since it makes it rather complicated to express what it means for elements to be equal to each other.
So I would suggest solving this issue by creating a User class like this:
class User {
String name;
String user_id;
User({required this.name, required this.user_id});
#override
int get hashCode => user_id.hashCode;
#override
bool operator ==(Object other) => other is User && user_id == other.user_id;
#override
String toString() => '{Name: $name, User ID: $user_id}';
}
class User {
String name;
String user_id;
User({required this.name, required this.user_id});
#override
int get hashCode => Object.hash(name, user_id);
#override
bool operator ==(Object other) =>
other is User && name == other.name && user_id == other.user_id;
#override
String toString() => '{Name: $name, User ID: $user_id}';
}
By doing so, we can do:
void main() {
List<User> userList = [
User(name: 'john', user_id: '251'),
User(name: 'will', user_id: '255'),
User(name: 'jack', user_id: '251'),
];
userList.forEach(print);
// {Name: john, User ID: 251}
// {Name: will, User ID: 255}
// {Name: jack, User ID: 251}
}
And we can then do the toSet() trick like this:
void main() {
List<User> userList = [
User(name: 'john', user_id: '251'),
User(name: 'will', user_id: '255'),
User(name: 'jack', user_id: '251'),
];
List<User> uniqueUserList = userList.toSet().toList();
uniqueUserList.forEach(print);
// {Name: john, User ID: 251}
// {Name: will, User ID: 255}
}
I notice that your example is made so you are only looking at the user_id to determine if you have a duplicate element. I don't know if your example is just wrong but if you want to compare both name and user_id your class would look like this:
class User {
String name;
String user_id;
User({required this.name, required this.user_id});
#override
int get hashCode => Object.hash(name, user_id);
#override
bool operator ==(Object other) =>
other is User && name == other.name && user_id == other.user_id;
#override
String toString() => '{Name: $name, User ID: $user_id}';
}
And finally, if you really want to solve this using Map objects, you could solve it using the following where you create a Set with your own definition of what it means to be equal:
void main() {
List<Map<String, String>> userList = [
{'name': 'john', 'user_id': '251'},
{'name': 'will', 'user_id': '255'},
{'name': 'jack', 'user_id': '251'} // duplicate
];
final set = LinkedHashSet<Map<String, String>>(
equals: (map1, map2) {
final id1 = map1['user_id'];
final id2 = map2['user_id'];
return id1 != null && id2 != null && id1 == id2;
},
hashCode: (map) => map['user_id'].hashCode,
);
set.addAll(userList);
List<Map<String, String>> uniqueUserList = set.toList();
uniqueUserList.forEach(print);
// {name: john, user_id: 251}
// {name: will, user_id: 255}
}
There are other ways to solve this but it will always get kinda ugly since Map is not intended for data structures as previous described.

Related

Dart parse json map with json_serializable, but with the key

Suppose I have the following json (structured as <String key, Map value>):
{
'A1': {'name': 'a'},
'B2': {'name': 'b'}
}
and I want to parse it to this class (notice that I use the key as the id for that user), using the fromJson factory method, which accepts two arguments:
Class User {
final String id;
final String name;
factory User.fromJson(Map<String, dynamic> json, String key) {
return User(
id: key,
name: json['name'],
);
}
}
Can I achieve it using json_serializable ?
The json Map expected by this factory method is just the values of the top-level JSON object you're parsing.
All you need to do is parse the JSON, extract all keys, then pass the values to the factory method.
Something like this:
import 'dart:convert';
const json = '''
{
"A1": {"name": "a"},
"B2": {"name": "b"}
}
''';
class User {
final String id;
final String name;
User({required this.id, required this.name});
factory User.fromJson(Map<String, dynamic> json, String key) {
return User(
id: key,
name: json['name'],
);
}
#override
String toString() => 'User(id=$id, name=$name)';
}
main() {
final map = jsonDecode(json);
map.forEach((id, userJson) {
final user = User.fromJson(userJson, id);
print(user);
});
}
Prints:
User(id=A1, name=a)
User(id=B2, name=b)
Now, to use json_serializable, just annotate it and replace your implementation with the generated one...
#JsonSerializable()
class User {
...
factory User.fromJson(Map<String, dynamic> json, String key) =>
// pass in only the relevant json Map!
_$UserFromJson(json[key]);
}

How to pass null in a method?

class Foo {
final int? i;
Foo({this.i});
Foo copyWith({int? x}) {
return Foo(i: x ?? i);
}
}
void main() {
final foo = Foo(i: 0);
foo.copyWith(x: null);
print(foo.i); // prints `0` but should print `null`.
}
How can I actually pass null value to the method? In earlier Dart version copyWith() and copyWith(x: null) were two different things.
Note: I'm not looking for workarounds like making a new variable, like isNull and then deciding whether to pass null or not based on its value.
With simple copyWithwhit Dart null-safety you can't override value by null because if id is null return this.id. You need to override the value by null but not return with another value. It can solve in a few ways but I will give you the best example.
void main() {
final user = User(name: 'Dave', id: 110);
User copy = user.copyWith(id: null);
print(copy.toString()); // prints User(name: Dave, id: null).
}
class User {
User({required this.name, this.id});
final String name;
final int? id;
UserCopyWith get copyWith => _UserCopyWith(this);
#override
String toString() => 'User(name: $name, id: $id)';
}
abstract class UserCopyWith {
User call({
String name,
int? id,
});
}
class _UserCopyWith implements UserCopyWith {
_UserCopyWith(this.value);
final User value;
static const _undefined = Object();
#override
User call({
Object name = _undefined,
Object? id = _undefined,
}) {
return User(
name: name == _undefined ? value.name : name as String,
id: id == _undefined ? value.id : id as int?,
);
}
}

How to validate the nested api objects in Playwright spi testing

I want to validate the nested api objects. I want to check if the value of 'id' inside the 'data' object is "1"
{
page: 1,
per_page: 6,
total: 12,
total_pages: 2,
data: [
{
id: 1,
email: 'george.bluth#reqres.in',
first_name: 'George',
last_name: 'Bluth',
avatar: 'https://reqres.in/img/faces/1-image.jpg'
}
]
}
How can I achieve this?
First you need to convert your json to a valid one.
And after in java you can do something like this.
public class Validation {
public static void main(String[] args) throws IOException {
String jsonAnswer = "{'page': 1,'per_page': 6,'total': 12,'total_pages': 2,'data':" +
" [{'id': 1,'email': 'george.bluth#reqres.in','first_name': 'George','last_name':" +
" 'Bluth','avatar': 'https://reqres.in/img/faces/1-image.jpg'}]}";
JsonObject json = JsonParser.parseString(jsonAnswer).getAsJsonObject();
int id = json.get("data")
.getAsJsonArray().get(0)
.getAsJsonObject().get("id").getAsInt();
if(1 == id){
System.out.println("Validation passed!");
}else{
System.out.println("Validation failed!");
}
}
}

How to do a switchmap or any better way to replace values in RxDart

I have a collection with chatroom information. Something like this:
{
chatroomid: 59,
members: [2,3]
}
Now what I want to do is, get the collection stream, in the course of doing that be able to replace the members string ids with a corresponding firestore document based on member id.
End result should look something like this:
{
chatroomid: 59,
members: [{
id: 2,
username: Johndoe1
},
{
id: 3,
username: Jennydoe1
}]
}
Is this possible with Dart RxDart?
Trying something like this fails:
getChatroomStream(chatroomid)
.switchMap((i) {
return Stream.value(i.members.map((e) => i.members.add(Document(path: 'Global.userRef/$e').streamData())));
})
.listen((event) {print(event);});
[VERBOSE-2:ui_dart_state.cc(177)] Unhandled Exception: Concurrent
modification during iteration: Instance of
'MappedListIterable<dynamic, void>'.
#0 ListIterator.moveNext (dart:_internal/iterable.dart:337:7)
class MemberInfo {
final int id;
final String? username;
final bool isLoading;
}
class Room {
final int chatroomid;
final List<int> members;
}
class RoomWithMemberInfos {
final int chatroomid;
final List<MemberInfo> infos;
factory RoomWithMemberInfos.initial(Room room) {
return RoomWithMemberInfos(
room.chatroomid,
room.members
.map((id) => MemberInfo(id, null, true))
.toList(growable: false)
);
}
RoomWithMemberInfos withInfo(MemberInfo info) {
return RoomWithMemberInfos(
chatroomid,
infos
.map((e) => e.id == info.id ? MemberInfo(e.id, info.name, false) : e)
.toList(growable: false)
);
}
}
Stream<MemberInfo> getMemberInfo(int id) { ... }
getChatroomStream()
.switchMap((Room room) {
final initial = RoomWithMemberInfos.initial(room);
return Stream
.fromIterable(room.members)
.flatMap(getMemberInfo)
.scan<RoomWithMemberInfos>(
(acc, info) => acc!.withInfo(info),
initial,
)
.startWith(initial);
});

Flutter / GraphQL - Mutation with custom type as parameter

I'm new to flutter and graphQL and currently I'm integrating mutations into my app. So, I have the server side using some custom types defined in the schema, but I don't know how to specify them on the flutter side. Let's see some code:
input DiaryGroupPermission {
groupId: Int!
permission: Int!
}
input DiaryInsideCommunity {
communityId: Int!
permissions: [DiaryGroupPermission]!
}
createDiary(community: DiaryInsideCommunity, description: String, title: String!): Diary
But on the client I don't know how to specify the DiaryInsideCommunity inside the mutation.
I've tried something like this:
String createDiary = """
mutation CreateDiary(\$title: String!, \$description: String!, \$community: DiaryInsideCommunity) {
createDiary(
title: \$title,
description: \$description,
community: \$community
) {
id
}
)}""".replaceAll('\n', ' ');
And passing my runMutation as follows:
runMutation({
"title": _generalPage.title(),
"description": _generalPage.description(),
"community": {
"communityId": 1,
"permissions": _permissionPage.selectedGroups().map((group) {
return {
"groupId": group.id,
"permission": 1,
};
}).toList(),
}
});
Any idea? Can't find anything on google.
Love to see the community that is created around the graphql_flutter library.
class DiaryGroupPermission {
int groupId;
int permission;
DiaryGroupPermission.fromJson(Map json)
: groupId = json['groupId'],
permission = json['permission'];
}
class DiaryInsideCommunity {
int communityId;
List<DiaryGroupPermission> permissions;
DiaryInsideCommunity.fromJson(Map json)
: communityId = json['communityId'],
permissions = json['permissions']
.map<DiaryGroupPermission>((Map permisionJson) =>
DiaryGroupPermission.fromJson(permisionJson))
.toList();
}
class Diary {
String body;
Diary(dynamic value) : body = value.toString();
}
typedef Diary createDiaryFunction(
DiaryInsideCommunity community, String description, String title);
DiaryInsideCommunity community = DiaryInsideCommunity.fromJson({
'communityId': 1,
'permissions': [
{'groupId': 1, 'permission': 1}
]
});
Diary mutation(DiaryInsideCommunity community,
{String description, #required String title}) =>
Diary(community.permissions[0].groupId);
Diary mutationResult = mutation(community, description: "a", title: "b");
I implemented the types that you wanted to in dart and created a mockup mutation function to show you how to call it.
There is no easier way to do types in dart.
Cheers from the creator of this library,
Eus
Assuming you are using graphql_flutter,
You may specify it in variables
an example is say you have this definitions for a mutation
type Mutation {
createMeterReading(
createMeterReadingInput: CreateMeterReadingInput
): MeterReading }
your input type definition
input CreateMeterReadingInput {
reading: Float
companyId: Int
companyStaffId: Int
customerId: Int
readingDataType: String
latitude: Float
longitude: Float
masterMeterId: Int
analogMeterId: Int
type: String
editedStatus: String
base64Image: String
readingTime: String
}
In flutter have
final response = await client.value.mutate(MutationOptions(
variables: {
'createMeterReadingInput': {
'reading': double.parse(_meterReadingController.text),
'companyStaffId': _decodedToken["companyStaffId"],
'analogMeterId': waterMeter["analogMeterId"],
'type': "actual",
'base64Image': getBase64(),
'readingTime': timeNow,
'latitude': widget?.currentPosition?.latitude,
'longitude': widget?.currentPosition?.longitude
}
},
documentNode: gql(r"""
mutation createMeterReading($createMeterReadingInput:CreateMeterReadingInput ) {
createMeterReading(createMeterReadingInput: $createMeterReadingInput) {
meterReadingId
reading
companyId
companyStaffId
imageUrl
editedStatus
companyStaff{
firstName
}
}
}
"""),
));

Resources