Remove duplicate from List<model> after merge - flutter

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

Related

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

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;
}
}

Dart: I want to check if the contents of 2 Lists are the same

One List is a List<String>? and the other is a List<dynamic>
I'd prefer not to change these data types. I just want to check if the contents are the same.
If I have a List [1, 2, 3] and a List [1, 2, 3] the output of a bool should be true
If I have a List [1, 2, 3] and a List [1, 3, 2] the output of a bool should be true
If I have a List [1, 2, 4] and a List [1, 2, 3] the output of a bool should be false
I will sort in this case and check equal like
final e1 = [1, 2, 3]..sort();
final e2 = [1, 3, 2]..sort();
print(e1.equals(e2)); //true
void main() {
List<int> a = [1, 2, 3];
List<dynamic> b = [1, 3, 3];
bool checkSame(List<dynamic> a, List<dynamic> b) {
var same = true;
if (a.length != b.length) {
same = false;
} else {
a.forEach((element) {
if (element.toString() != b[a.indexOf(element)].toString()) {
same = false;
}
});
}
return same;
}
bool val = checkSame(a, b);
print(val);
}
I recommend to use collection package with 564 like on pub.dev. to compare lists/maps/sets
i found from here https://stackoverflow.com/a/63633370/12838877
To compare list of integer and list of dynamic
import 'package:collection/collection.dart';
List<int> a = [1,2,4,5,6];
List<dynamic> b = [1,2,4,5,6];
List<dynamic> c = [1,4,5,6,2];
bool isEqual = DeepCollectionEquality().equals(a,b);
bool isEqual2 = DeepCollectionEquality().equals(a,c);
print(isEqual); // result is true without any error
print (isEqual2); // result is false , since its not ordered
UPDATE
if you want to compare 2 list dynamic unordered you can use code below
final unOrderedList = DeepCollectionEquality.unordered().equals(a,c);
print(unOrderedList); // result true
since its dynamic list, its also can compare between list that contain int,null, string ,list , etc,
List<dynamic> d = [1,"abc",2, null, ["a"], 4];
List<dynamic> e = [1,"abc",2, null, ["a"], 4];
final compare2list = DeepCollectionEquality.unordered().equals(d,e);
print(compare2list); // result true

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
}

In dart,How to remove element in the NestedList

Element not removed from the List. pls tell me how could i remove the element in the list
void main() {
List data=[['apple',1],['banana',5]];
data.remove(['apple',1]);
print(data);
}
Instead of defining dynamic objects like ['apple', 1]. Declare a class for it, and tell the program how those instances should be compared such as
class Fruit {
final String name;
final int index;
Fruit(this.index, this.name);
#override
int get hashCode => name.hashCode + index.hashCode * 7;
}
and then use it like;
void main() {
List data=[Fruit('apple', 1), Fruit('banana', 5),];
data.remove(['apple',1]);
print(data);
}
It's not very recommended to use List<dynamic> everywhere in dart. Tolga Kartal's answer gives a better practice.
Bur for your case, if you do not want to refactor your code, you can first find where ['apple', 1] is and then delete it from data.
void main() {
List data=[['apple',1],['banana',5]];
dynamic targetElement = data.firstWhere(
(element) => element[0]=='apple' && element[1]==1,
orElse: () => null);
if (targetElement != null)
data.remove(targetElement);
print(data);
}
The reason why you can't directly use data.remove(['apple', 1]) is that every time you use ['apple', 1], what you're actually doing is declaring a new List object. Although both ['apple', 1] have exactly same elements, their addresses in memory are different. To be more specific, they have different hash codes.
void main() {
List<dynamic> itemA = ['apple', 1];
List<dynamic> itemB = ['apple', 1];
print('hashcode of itemA and itemB');
print('itemA: ${itemA.hashCode}, itemB: ${itemB.hashCode}');
// <<< itemA: 397807318, itemB: 278500865
print('verify if they have same elements inside');
print('itemA[0] == itemB[0]:${itemA[0] == itemB[0]}, itemA[1] == itemB[1]:${itemA[1] == itemB[1]}');
// <<< itemA[0] == itemB[0]:true, itemA[1] == itemB[1]:true
print('check if itemA and itemB are same');
print('itemA == itemB: ${itemA == itemB}');
// <<< itemA == itemB: false
print('A case to show why they are different');
itemA.add('Hello');
itemB.add('World');
print('itemA: $itemA');
// <<< itemA: [apple, 1, Hello]
print('itemB: $itemB');
// <<< itemB: [apple, 1, World]
}
Hope this explanation helps.
Just replace ['apple',1] to index, In this case 0
void main() {
List data=[['apple',1],['banana',5]];
data.remove(0);
print(data);
}
Hope it work

sort list based on boolean

I want to sort a list based on a boolean using Comparable in dart. I tried the following but was not able to do it.
In the list, all the elements which are true should come first rest of the list should remain as it is.
class Item implements Comparable<Item> {
int id;
String name;
int price;
bool isAvailable;
Item({this.id, this.name, this.price, this.isAvailable = false});
#override
int compareTo(Item other) {
if (isAvailable) {
return -1;
}
return 0;
}
}
void main() {
Item item = new Item(id: 1, name: "Item one", price: 1000);
Item item2 = new Item(id: 2, name: "Item two", price: 2000);
Item item3 =
new Item(id: 3, name: "Item three", price: 500, isAvailable: true);
List<Item> items = [item, item2, item3];
items.sort();
items.forEach((Item item) {
print('${item.id} - ${item.name} - ${item.price}');
});
}
This should print
3 - Item three - 500
1 - Item one - 1000
2 - Item two - 2000
3 - Item three - 500 should come first because it is true but it is printing
1 - Item one - 1000
2 - Item two - 2000
3 - Item three - 500
What am I doing wrong?
This code can be run as it is on Dartpad here
A compareTo implementation should be reflexive, anti-symmetric, and transitive. Violating these properties can give sort results that are not self-consistent.
As written, your compareTo claims that two elements are always considered "equal" in sort order if this.isAvailable is false. But what about if other.isAvailable is true?
Your sort should work if you implement compareTo properly without trying to take shortcuts:
int compareTo(Item other) {
if (isAvailable == other.isAvailable) {
return 0;
} else if (isAvailable) {
return -1;
}
return 1;
}