I have two List of Model . How can I get the difference between them? - flutter

List a = [
AbsentModel(name: "abir", id: 1),
AbsentModel(name: "fahim", id: 2),
AbsentModel(name: "rahim", id: 3),
AbsentModel(name: "akash", id: 4), ]
List b = [
AbsentModel(name: "akash", id: 4),
AbsentModel(name: "fahim", id: 2),
AbsentModel(name: "rahim", id: 3),]
`
I need the output of -
the difference between List a and List b
result -
`List c = [ AbsentModel(name: "abir", id: 1),];
I have tried to toSet() but it only can give me the result If i made all list without model.
Like if made simple id List then it works.
But can not get the difference when I am using model data.

This code would work fine as others. You just need to use equatable package.
void main() {
List a = [
AbsentModel(name: "abir", id: 1),
AbsentModel(name: "fahim", id: 2),
AbsentModel(name: "rahim", id: 3),
AbsentModel(name: "akash", id: 4), ]
List b = [
AbsentModel(name: "akash", id: 4),
AbsentModel(name: "fahim", id: 2),
AbsentModel(name: "rahim", id: 3),]
List<AbsentModel> c = a.where((item) => !b.contains(item)).toList();
print(c);
}
However, you need to redefine the AbsentModel as follows:
import 'package:equatable/equatable.dart';
class AbsentModel extends Equatable {
final String name;
final int id;
AbsentModel({required this.name, required this.id,});
#override
List<Object> get props => [name, id];
}
Equatable overrides == and hashCode for you so you don't have to waste your time writing lots of boilerplate code.

The first answer is correct, but does not take into account the fact that the deviating value would not be recognised if it were in list b.
This solution is similar to the above one, but checks the difference from a to b and from b to a. Also it is written as an extension for generic List, so it can be used for all kind of lists.
extension Difference<T> on List<T> {
List<T> difference(List<T> to) {
final diff = where((item) => !to.contains(item)).toList();
diff.addAll(to.where((item) => !contains(item)));
return diff;
}
main() {
...
final diff = a.difference(b);
}
Also you do not have to use the Equatable package (if you don't want to), since you could overload the == operator:
class AbsentModel {
final String name;
final int id;
AbsentModel({required this.name, required this.id});
#override
bool operator ==(Object other) {
return (other is AbsentModel) && other.id == id && other.name == name;
}
}

Related

how to sum list values from API in flutter

Does anyone here know/have references/examples of how to add up the values in the list in Flutter. Thanks
use sum:
import 'package:collection/collection.dart';
void main() {
final list = [1, 2, 3, 4];
final sum = list.sum;
print(sum); // prints 10
}
Your question is similar to the question here, refer to it for more information
you can use .fold() method
fold method:
T fold<T>(T initialValue, T Function(T, Data) combine)
example for sum list of object:
void main() {
List<Data> listData = [
Data(count: 10, name: 'a'),
Data(count: 12, name: 'bc'),
Data(count: 21, name: 'abc'),
];
int sum = listData.fold(0, (int preValue, data) => preValue + data.count);
print(sum);// 43
}
class Data {
int count;
String name;
Data({required this.count, required this.name});
}

flutter - check if list contains value from another list

I have two lists, one with posted images and a second with friends.
Only friends posts should be displayed from the posts list.
In this case for Obi.
class postModel{
String? image;
String? userId;
String? name;
int? age;
postModel({this.image, this.userId, this.name, this.age});
}
List<postModel> imageList = [
postModel(image: "imageUrl", userId: "1gw3t2s", name: "Luke", age: 21),
postModel(image: "imageUrl2", userId: "hjerhew", name: "Joda", age: 108),
postModel(image: "imageUrl3", userId: "475fdhr", name: "Obi", age: 30),
postModel(image: "imageUrl4", userId: "jrt54he", name: "Vader", age: 35),];
class friendModel{
String? userId;
String? name;
friendModel({this.userId, this.name});
}
List<friendModel> friendList = [
friendModel(userId: "1gw3t2s", name: "Luke"),
friendModel(userId: "hjerhew", name: "Joda"),];
//...
ListView.builder(
itemCount: imageList.length,
itemBuilder: (context, i) {
return friendList.contains(imageList[i].userId) //something like that
?Image.network(imageList[i].image)
:Container();
}
Output should be only the post from Luke and Joda
thanks
Initialise a new list a and add data to it like below
List<friendModel> a = [];
for(var img in imageList){
for(var frnd in friendList){
if(img.name == frnd.name){
a.add(frnd);
}
}
}
print(a);
If you wanted to avoid double for loops. You could use something like:
for(int i = 0; i < friendList.length; i++) {
var test = imageList.where((e) => e.userId ==
friendList[i].userId).toList();
print(test[0].image);
}
but replace the test var with another list that you can then add to or customize with whatever works for your application.

Reorder Array of objects Flutter

Array of object
Input:
[
{id:1,order:1},
{id:2,order:null},
{id:3,order:0},
{id:4,order:null},
{id:5,order:3}
]
Output:
[
{id:3,order:0},
{id:1,order:1},
{id:2,order:null},
{id:5,order:3},
{id:4,order:null}
]
Considering model
Item(int id,int? Order)
By default the order is null and these positions are to be maintained and object having orders are to be moved up or down.
Try this, if the array is of type Map -
arrayOfObjects.sort((a, b) => a['order'].compareTo(b['order']));
Or this if it is holding Item class with an order attribute
arrayOfObjects.sort((Item a, Item b) => a.order.compareTo(b.order));
Note - You can remove items with null order before running the sort.
Example
arrayOfObjects.removeWhere((item)=> item.order == null);
The double Iterations are based on the length of the array to handle the nulls.
Solution
import 'package:collection/collection.dart';
class Item {
int? _id;
int? _order;
Item({int? id, int? order}) {
this._id = id;
this._order = order;
}
int? get id => _id;
set id(int? id) => _id = id;
int? get order => _order;
set order(int? order) => _order = order;
Item.fromJson(Map<String, dynamic> json) {
_id = json['id'];
_order = json['order'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this._id;
data['order'] = this._order;
return data;
}
}
List<Item> reorder(List<Item> it){
var tempData = it;
tempData.forEach((_){
tempData.forEachIndexed((index,val){
///Remove original and replace
var ind = val.order;
if(ind!=null){
///Check if it is at the Proper Position
if (index == ind) {
return;
}
var first = it.removeAt(index);
it.insert(ind as int, first);
}
});
});
return it;
}
void main() {
var list = [
Item(id: 1, order: 1),
Item(id: 3, order: 2),
Item(id: 2, order: 7),
Item(id: 4, order: null),
Item(id: 5, order: null),
Item(id: 6, order: null),
Item(id: 7, order: 6),
Item(id: 8, order: 4)
];
list.forEach((it) => print('${it.id} ->${it.order}'));
var first = reorder(list);
print('\n');
first.forEach((it) => print('${it.id} ->${it.order}'));
///Stack List
}

Remove duplicate from List<model> after merge

I want to add a list to my main List and remove duplicate, like this:
class item {
int id;
String title;
item({this.id, this.title});
}
void main() {
// this is working for List<int>
List<int> c = [1, 2, 3];
List<int> d = [3, 4, 5];
c.addAll(d..removeWhere((e) => c.contains(e)));
print(c);
// but this is not working for List<item>
List<item> a = new List<item>();
a.add(new item(id: 1, title: 'item1'));
a.add(new item(id: 2, title: 'item2'));
List<item> b = new List<item>();
b.add(new item(id: 2, title: 'item2'));
b.add(new item(id: 3, title: 'item3'));
a.addAll(b..removeWhere((e) => a.contains(e)));
a.forEach((f) => print('${f.id} ${f.title}'));
}
and output is like this:
[1, 2, 3, 4, 5]
1 item1
2 item2
2 item2
3 item3
As you test this code on https://dartpad.dev/ output is ok for List<int> but there is duplicate in output for List<item>.
The first list have integer values and when you call contains it will check the values and will work correctly.
In second case you have item objects. Both lists have objects that may have same property values but both are two different object. For example, the below code will work correctly in your case, because the item2 object is same in both lists.
Item item2 = Item(id: 2, title: 'item2');
List<Item> a = new List<Item>();
a.add(new Item(id: 1, title: 'item1'));
a.add(item2);
List<Item> b = new List<Item>();
b.add(item2);
b.add(new Item(id: 3, title: 'item3'));
When you call contains it will use the Object.== method, so to handle this issue you have to override that method and specify your own equality logic.
class Item {
int id;
String title;
Item({this.id, this.title});
#override
bool operator == (Object other) {
return
identical(this, other) ||
other is Item &&
runtimeType == other.runtimeType &&
id == other.id;
}
}
Or you can use the equatable package to handle it better.
References:
contains method
operator == method
I think you need to iterate on your list a if you want to compare a property (e.g title)
a.addAll(
b
..removeWhere((e) {
bool flag = false;
a.forEach((x) {
if (x.title.contains(e.title)) {
flag = true;
}
});
return flag;
}),
);
As suggested below, those two list items are different
Thats because these 2 item's:
a.add(new item(id: 2, title: 'item2'));
b.add(new item(id: 2, title: 'item2'));
are different. They are 2 instances of 2 different objects that just have the same values for id and title. As the documentation tells:
The default behavior for all Objects is to return true if and only if this and other are the same object.
If you want to compare if the 2 fields are the same you can override the equality operator inside your item class:
operator ==(item other) {
return (this.id == other.id && this.title == other.title);
}
which gives the expected output:
[1, 2, 3, 4, 5]
1 item1
2 item2
3 item3

Use Isolate to sort list

I have a non-primitive list which I would like to sort.
When I sort it, the UI thread is blocked and the app freezes for a few seconds.
I tried to avoid this by using dart's Isloate compute function but since the parameter sent to the compute function must be a primitive or a list/map of primitives (send method) it didn't work.
To conclude, is there any way to perform a list sort(non-primitive) without blocking the UI thread?
Edit: Clarification - I was trying to call a function through compute and I was passing a list of objects (which I got from a third party plugin) as an argument, those objects had a property of type Iterable and that caused everything to fail - make sure all the types are primitive or List/Map of primitives. With the answers I received and changing the type from Iterable to List it worked.
I'm not sure if I understood your question, but you can sort a list of non primitive elements like this:
final List<Element> elements = [
Element(id: 1),
Element(id: 7),
Element(id: 2),
Element(id: 0)
];
elements.sort((a, b) => a.compareTo(b));
// or
elements.sort((a, b) => a.id > b.id ? 1 : -1);
This would be a print(elements); output:
I/flutter ( 7351): [id: 0, id: 1, id: 2, id: 7]
And this would be the class Element
class Element {
final int id;
Element({this.id});
#override
String toString() => "id: $id";
int compareTo(Element other) => this.id > other.id ? 1 : -1;
}
Edit: To make this asynchronously, you could do this:
Future<List<Element>> asyncSort() async {
print("before sort: $elements");
elements = await compute(_sort, elements);
print("after sort: $elements");
return elements;
}
static List<Element> _sort(List<Element> list) {
list.sort((a, b) => a.compareTo(b));
return list;
}
print("before calling asyncSort(): $elements");
asyncSort();
print("after calling asyncSort(): $elements");
And this would be the output:
I/flutter ( 7351): before calling asyncSort(): [id: 1, id: 7, id: 2, id: 0]
I/flutter ( 7351): before sort: [id: 1, id: 7, id: 2, id: 0]
I/flutter ( 7351): after calling asyncSort(): [id: 1, id: 7, id: 2, id: 0]
I/flutter ( 7351): after sort: [id: 0, id: 1, id: 2, id: 7]
Edit2: If you want to send a compare function to compute, you could use a Map or a List of arguments with the list and the compare function and pass that instead of the list, because compute just takes one argument. Here is an example:
Future<List<Element>> asyncSort() async {
print("before sort: $elements");
Map args = {"list": elements, "compare": compare};
elements = await compute(_sortWith, args);
print("after sort: $elements");
return elements;
}
static List<Element> _sortWith(Map args) {
List<Element> list = args["list"];
Function(Element a, Element b) compare = args["compare"];
list.sort((a, b) => compare(a, b));
return list;
}
static int compare(Element a, Element b) {
return a.id > b.id ? 1 : -1;
}
This is how i use compute, just put all parameters to a list, then call it in a List of dynamic object:
image = await compute(getCropImage, [copyFaces, streamImg]);
imglib.Image getCropImage(List<dynamic> values) {
var face = values[0]; // copyFaces
var image = values[1]; // streamImg
}