Dart compare unordered Lists with Objects - list

I have following problem. There are two Lists with Articles in it. In the following example the result prints me false. But the Articles are the same. I think thats, because these are different objects, if I add in both lists article1, it will be true.
I also tried DeepCollectionEquality.unordered().equals from this issue:
How can I compare Lists for equality in Dart?
But it is also giving me FALSE back.
In my real project, I have two Lists with Articles in it. These lists are not sorted, so one Article can be the first in one list, and an article with the same id and name can be the last one in the other list. But if both lists have the same articles (with the same name and id) it should result with true.
var a = List<Article>();
var b = List<Article>();
var article1 = Article(id: "1", name: "Beer");
var article2 = Article(id: "1", name: "Beer");
a.add(article1);
b.add(article2);
print(listEquals(a, b));

As you said , those are different objects, you need to override the equal operator of your class, like this:
class Article {
final String name;
final String id;
const Article({this.id,this.name});
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Article &&
runtimeType == other.runtimeType &&
id == other.id;
#override
int get hashCode => id.hashCode;
}
Then the result will be true, because the ids are the same.
Also you can take a look at this package
https://pub.dev/packages/equatable

As my solution I used the "equatable"- package: https://pub.dev/packages/equatable
For checking an unordered List, I use DeepCollectionEquality.unordered().equals instead of listEquals
var a = List<Article>();
var b = List<Article>();
var article1 = Article(id: "1", name: "Beer");
var article2 = Article(id: "2", name: "Tequilla");
var article3 = Article(id: "3", name: "VodkaBull");
var article4 = Article(id: "1", name: "Beer");
var article5 = Article(id: "2", name: "Tequilla");
var article6 = Article(id: "3", name: "VodkaBull");
a.add(article1);
a.add(article2);
a.add(article3);
b.add(article4);
b.add(article5);
b.add(article6);
print(listEquals(a, b));
print(DeepCollectionEquality.unordered().equals(a, b));
The Code for my Article looks as following:
import 'package:equatable/equatable.dart';
class Article extends Equatable {
String id;
String name;
Article({this.id, this.name});
#override
// TODO: implement props
List<Object> get props => [id, name];
}

Related

how to filter list object by using stream map filter in java

i want to filter a list of student in java. I have a student class in kotlin like this.
class Student(
var id: String? = null,
var firstName: String? = null,
var lastName: String? = null
) {
constructor(entity: StudentCourse?): this() {
if (entity != null) {
this.id = entity.id.id
this.name = entity.name
}
}
}
class StudentCourse (#EmbeddedId open var id: StudentCourseId) {
constructor() : this(StudentCourseId())
open var name: Boolean? = null
}
#Embeddable
open class StudentCourseId: Serializable {
open var id: String? = null
open var deptName: String? = null
}
this is the list i want to filter :
var students: List<Student> = listOf(
Student("14adbv45", "dan", "GEG"),
Student("96adbv42","Bob", "Bowyer"),
Student("30adbv45","Emily", "Eden")
)
I do this
List<students> studentListContainsFirstNameBob = students.stream()
.map(StudentCourse)
.filter(e -> e.getFirstName.equals("Bob"))
.flatMap(List::stream);
but it doesn't work.
How can i do it please
There are multiple issues in your code.
For example in this part:
constructor(entity: StudentCourse?): this() {
if (entity != null) {
this.id = entity.id.id
this.name = entity.name
}
}
The entity.name refers to StudentCourse#name, but this property is actually of Boolean type, so comparing it to String doe snot make much sense. You have also doubled .id which is incorrect.
Next thing, I am not sure what this snipped should do, was the intention to link a student with given course? If so, you would probably like to add a list of students to a course, or a list of courses to a student (which sounds more correct).
Finally, when it comes to filtering a list, you can get students with first name Bob in this way:
var studentListContainsFirstNameBob: List<Student> = students
.filter { it.firstName.equals("Bob") }
.toList()
Mind the it variable refers to the element from the list, it could also be written:
var studentListContainsFirstNameBob: List<Student> = students
.filter { student -> student.firstName.equals("Bob") }
.toList()

How to add elements dynamically in a 2d list from another list in Flutter?

I have a list of model class objects. Such as -
List<ModelChannel> allChannels = [];
I have added elements in this list from json. Model Class variables are-
final String channelid;
final String channelname;
final String channeltype;
final String categoryname;
final String channelimage;
final String channelurl;
Here categorytype contains country information. I want to divide the list country wise dynamically. I have intended to use 2d list where each row will contain all the channels of a specific country. Is this the right approach? If yes how to implement this and if not what will be the right one?
If I understand correctly, you are looking for groupBy function from collection package.
Add this package to your pubspec.yaml:
dependencies:
collection: any
And use groupBy:
import 'package:collection/collection.dart';
...
final groupByCountry = groupBy(allChannels, (ModelChannel e) => e.categoryname);
List<List<ModelChannel>> countryList = [];
List<String> channelType = [];
allChannels.forEach((element) {
if (channelType.isEmpty) {
channelType.add(element.channeltype);
} else {
if (channelType.contains(element.channeltype)) {
} else {
channelType.add(element.channeltype);
}
}
});
channelType.forEach((countryCode) {
List<ModelChannel> t = [];
allChannels.forEach((element) {
if (element.channeltype == countryCode) {
t.add(element);
}
});
countryList.add(t);
});

How can I distinct a complex object list in DART

I have one list of complex object. How can I distinct the list using their IDs?
I cant use toSet and similars, because the hashcode from the objects all are diferent.
1) Vanilla Dart
Loop through the list, adding IDs to a set as you go. Whenever you add an ID to the set that didn't already exist, add that element to a new list of distinct values.
void main() {
var list = [
Data('a'),
Data('a'),
Data('b'),
Data('c'),
];
var idSet = <String>{};
var distinct = <Data>[];
for (var d in list) {
if (idSet.add(d.id)) {
distinct.add(d);
}
}
}
class Data {
Data(this.id);
final String id;
}
2) Packages
Several packages exist that expand on default the Iterable utility methods, such as flinq or darq. They add a distinct method you can call to easily get a list of unique members of a list based on some property of the members.
import 'package:darq/darq.dart';
void main() {
var list = [
Data('a'),
Data('a'),
Data('b'),
Data('c'),
];
var distinct = list.distinct((d) => d.id).toList();
}
(Disclaimer, I am the maintainer of darq.)
Try to use this extension:
extension IterableExtension<T> on Iterable<T> {
Iterable<T> distinctBy(Object getCompareValue(T e)) {
var result = <T>[];
this.forEach((element) {
if (!result.any((x) => getCompareValue(x) == getCompareValue(element)))
result.add(element);
});
return result;
}
}
Using:
var distinctList = someList.distinctBy((x) => x.oid);
Or you can use a hash there.

Flutter Comparing 2 lists of objects using map and contains not working

I have 2 lists of Objects namely newList and oldList as shown below:
newList: [Object{id: -LhnrmWPWN2X_cWdIAQW, title: , category: abandoned, latitude: -17.8594103, longitude: 30.9615846}, Object{id: -LhnpMHQ3l288W28qoDW, title: , category: potholes, latitude: -17.8593472, longitude: 30.9614917}]
oldList: [Object{id: -LhnpMHQ3l288W28qoDW, title: , category: potholes, latitude: -17.8593472, longitude: 30.9614917}]
The problem is that using contains is not working when checking if all objects in newList are in oldList using the following code:
newList.where((Object p) => !oldList.contains(p))
.map((Object obj) => print('\n\n\n\ntest \n$obj'))
.toList();
In fact this code is returning true for both instances of the object in newList.
I expect that the code should return true for only one of the objects.
Please assist.
I think you want to check is two objects are equal or not,
In Dart by default, == returns true if two objects are the same instance the contains is the same too.
In addition, you can use the equatable package to be able to compare objects.
or as equatable package provides, you can do it without the package, you need to override == method in your object and hashCode staff.
class Person {
final String name;
const Person(this.name);
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Person &&
runtimeType == other.runtimeType &&
name == other.name;
#override
int get hashCode => name.hashCode;
}
but I would recommend to use the equatable package
import 'package:equatable/equatable.dart';
class Person extends Equatable {
final String name;
Person(this.name) : super([name]);
}
Seems like you're looking for whether oldList doesn't contain the object in your code snippet. Try utilising this code.
newList.where((i) => oldList.contains(i)).map((obj) {
print('${obj.id}');
return obj;
}).toList();
Here is a little snippet on the workings of the code above.

Swift 3, Sort an Array of Dictionaries

I'm having a heck of a time in Swift 3 sorting an array of dictionaries.
In Swift 2, I would do it this way, which worked fine:
var dicArray = [Dictionary<String, String>()]
let dic1 = ["last": "Smith", "first": "Robert"]
dicArray.append(dic1)
let dic2 = ["last": "Adams", "first": "Bill"]
dicArray.append(dic2)
let sortedArray = dicArray.sort { ($0["last"] as? String) < ($1["last"] as? String) }
Converting the same code to Swift 3 has not gone well. The system guided me to this (through a circuitous route):
let sortedArray = dicArray.sorted { ($0["last"]! as String) < ($1["last"]! as String) }
But the app always crashes, with the error that it found nil while unwrapping an Optional value.
After banging my head against the table for too long, putting ?s and !s in every imaginable combination, I resorted to an old approach to get the job done:
let sortedArray = (dicArray as NSArray).sortedArray(using: [NSSortDescriptor(key: "last", ascending: true)]) as! [[String:AnyObject]]
That works, and I'm moving along, but it's not very Swifty, is it?
Where did it all go wrong? How can I make the pure Swift sort function work in a case like this?
Where did it all go wrong?
It went wrong on your first line:
var dicArray = [Dictionary<String, String>()]
That never did what you want, even in Swift 2, because you are actually inserting an extra, empty dictionary into the array. That's where the crash comes from; the empty dictionary has no "last" key, because it is, uh, empty.
You want this:
var dicArray = [Dictionary<String, String>]()
See the difference? After that change, everything falls into place:
var dicArray = [Dictionary<String, String>]()
let dic1 = ["last": "Smith", "first": "Robert"]
dicArray.append(dic1)
let dic2 = ["last": "Adams", "first": "Bill"]
dicArray.append(dic2)
let sortedArray = dicArray.sorted {$0["last"]! < $1["last"]!}
// [["first": "Bill", "last": "Adams"], ["first": "Robert", "last": "Smith"]]
Rather than using dictionaries with a fixed set of keys, it's generally advisable to create your own custom types:
struct Person {
let lastName: String
let firstName: String
}
This way, you never have to worry about whether you got the key for a particular value in a dictionary right, because the compiler will enforce checks for the names of the property. It makes it easier to write robust, error-free code.
And, coincidentally, it makes sorting cleaner, too. To make this custom type sortable, you make it conform to the Comparable protocol:
extension Person: Comparable {
public static func ==(lhs: Person, rhs: Person) -> Bool {
return lhs.lastName == rhs.lastName && lhs.firstName == rhs.firstName
}
public static func < (lhs: Person, rhs: Person) -> Bool {
// if lastnames are the same, compare first names,
// otherwise we're comparing last names
if lhs.lastName == rhs.lastName {
return lhs.firstName < rhs.firstName
} else {
return lhs.lastName < rhs.lastName
}
}
}
Now, you can just sort them, keeping the comparison logic nicely encapsulated within the Person type:
let people = [Person(lastName: "Smith", firstName: "Robert"), Person(lastName: "Adams", firstName: "Bill")]
let sortedPeople = people.sorted()
Now, admittedly, the above dodges your implicit question of how to compare optionals. So, below is an example where firstName and lastName are optionals. But, rather than worrying about where to put the ? or !, I'd use nil-coalescing operator, ??, or a switch statement, e.g.:
struct Person {
let lastName: String?
let firstName: String?
}
extension Person: Comparable {
public static func ==(lhs: Person, rhs: Person) -> Bool {
return lhs.lastName == rhs.lastName && lhs.firstName == rhs.firstName
}
public static func < (lhs: Person, rhs: Person) -> Bool {
// if lastnames are the same, compare first names,
// otherwise we're comparing last names
var lhsString: String?
var rhsString: String?
if lhs.lastName == rhs.lastName {
lhsString = lhs.firstName
rhsString = rhs.firstName
} else {
lhsString = lhs.lastName
rhsString = rhs.lastName
}
// now compare two optional strings
return (lhsString ?? "") < (rhsString ?? "")
// or you could do
//
// switch (lhsString, rhsString) {
// case (nil, nil): return false
// case (nil, _): return true
// case (_, nil): return false
// default: return lhsString! < rhsString!
// }
}
}
The switch statement is more explicit regarding the handling of nil values (e.g. nil sorted before or after non-optional values) and will distinguish between a nil value and an empty string, should you need that. The nil coalescing operator is simpler (and IMHO, more intuitive for the end-user), but you can use switch approach if you want.
let descriptor: NSSortDescriptor = NSSortDescriptor.init(key: "YOUR KEY", ascending: true)
let sortedResults: NSArray = tempArray.sortedArray(using: [descriptor]) as NSArray