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
Related
2> as you can see below i have two list of object and i want to merge into single it should compare list based on date
//here is the list 1
List<Object1> list1=[
Object1("date":"1","day_data":12),
Object1("date":"2","day_data":15),
]
//here is the list 2
List<Object2> list2=[
Object2("date":"1","night_data":56),
Object2("date":"3","night_data":80),
];
//expected output
List<Object3> expectedList=[
Object3("date":"1","day_data":12,"night_data":56),
Object3("date":"2","day_data":15,"night_data":null),
Object3("date":"3","day_data":null,"night_data":80),
];
The code below should do the trick. It uses a Map where the keys are, let's say, the Primary Key. And the values are the reduce from list1 and list2 (It even merges duplicated items by date from list1 and/or list2). At the end, I've added some asserts to actually test if it works.
Here's also the DartPad to run it online.
class Object1 {
final String date;
final int day_data;
const Object1({required this.date, required this.day_data});
}
class Object2 {
final String date;
final int night_data;
const Object2({required this.date, required this.night_data});
}
class Object3 {
final String date;
final int? day_data;
final int? night_data;
const Object3({required this.date, this.day_data, this.night_data});
}
List<Object3> merge(List<Object1> obj1List, List<Object2> obj2List) {
final map = <String, Object3>{};
obj1List.forEach((obj1) =>
map.update(
obj1.date,
(obj3) => Object3(date: obj3.date, day_data: obj1.day_data, night_data: obj3.night_data),
ifAbsent: () => Object3(date: obj1.date, day_data: obj1.day_data, night_data: null),
));
obj2List.forEach((obj2) =>
map.update(
obj2.date,
(obj3) => Object3(date: obj3.date, day_data: obj3.day_data, night_data: obj2.night_data),
ifAbsent: () => Object3(date: obj2.date, day_data: null, night_data: obj2.night_data),
));
return map.values.toList()
..sort((a, b) => a.date.compareTo(b.date));
}
void main() {
//here is the list 1
List<Object1> list1=[
Object1(date:"1",day_data:12),
Object1(date:"2",day_data:15),
];
//here is the list 2
List<Object2> list2=[
Object2(date:"1",night_data:56),
Object2(date:"3",night_data:80),
];
List<Object3> actualList = merge(list1, list2);
//expected output
List<Object3> expectedList=[
Object3(date:"1",day_data:12,night_data:56),
Object3(date:"2",day_data:15,night_data:null),
Object3(date:"3",day_data:null,night_data:80),
];
print('Checking size...');
assert(actualList.length == expectedList.length);
print('OK');
print('Checking items...');
actualList.asMap().forEach((i, actual) {
final expected = expectedList[i];
print(' Checking item $i...');
assert(actual.date == expected.date);
assert(actual.day_data == expected.day_data);
assert(actual.night_data == expected.night_data);
print(' OK');
});
print('OK');
}
You need to do manually with two loops and comparing dates.
Hey you can achieve by compering two list and get list like below -
void compareList(){
List<ObjectModel> list1=[
ObjectModel(date:"1",dayData:12),
ObjectModel(date:"2",dayData:15),
];
//here is the list 2
List<ObjectModel> list2=[
ObjectModel(date:"1",nightData:56),
ObjectModel(date:"3",nightData:80),
];
//expected output
List<ObjectModel> expectedList= [];
list1.forEach((element) {
ObjectModel innerObject = list2.firstWhere((ObjectModel innerElement) => element.date == innerElement.date, orElse: (){return ObjectModel();});
if(innerObject.date !=null){
expectedList.add(ObjectModel(date:element.date,dayData:element.dayData,nightData: innerObject.nightData));
}else{
expectedList.add(element);
}
});
list2.forEach((element) {
ObjectModel innerObject = list1.firstWhere((ObjectModel innerElement) => element.date == innerElement.date, orElse: (){return ObjectModel();});
if(innerObject.date ==null){
expectedList.add(element);
}
});
print(expectedList.length);
}
class ObjectModel{
String? date;
int? dayData;
int? nightData;
ObjectModel({ this.date, this.dayData, this.nightData});
}
I am streaming api. With the API, I get 1 item each and add to the list. The fact is that the api stream works in a circle, and duplicates are added to the list. How can I eliminate duplicates?
Code add list:
groupData.map((dynamic item) => GetOrder.fromJson(item))
.where((element) {
if (element.orderId != null) {
if (!list.contains(element)) {
list.add(element);
}
return true;
} else {
return false;
}
}).toList();
If elements are primitives, you can use a Set:
final myList = ['a', 'b', 'a'];
Set.from(myList).toList(); // == ['a', 'b']
but if elements are objects, a Set wouldn't work because every object is different from the others (unless you implement == and hashCode, but that goes beyond this answer)
class TestClass {
final String id;
TestClass(this.id);
}
...
final myClassList = [TestClass('a'), TestClass('b'), TestClass('a')];
Set.from(myClassList).toList(); // doesn't work! All classes are different
you should filter them, for example creating a map and getting its values:
class TestClass {
final String id;
TestClass(this.id);
}
...
final myClassList = [TestClass('a'), TestClass('b'), TestClass('a')];
final filteredClassList = myClassList
.fold<Map<String, TestClass>>({}, (map, c) {
map.putIfAbsent(c.id, () => c);
return map;
})
.values
.toList();
That said, this should work for you
groupData
.map((dynamic item) => GetOrder.fromJson(item))
.fold<Map<String, GetOrder>>({}, (map, element) {
map.putIfAbsent(element.orderId, () => element);
return map;
})
.values
.toList();
You can use Set instead
A Set is an unordered List without duplicates
If this is not working, then chances are that u have different object for the same actual object. (meaning, you have in 2 different places in memory)
In this case .contains or Set will not work
Prior to null-safe dart, the following was valid syntax:
final list = [1, 2, 3];
final x = list.firstWhere((element) => element > 3, orElse: () => null);
if (x == null) {
// do stuff...
}
Now, firstWhere requires orElse to return an int, opposed to an int?, therefore I cannot return null.
How can I return null from orElse?
A handy function, firstWhereOrNull, solves this exact problem.
Import package:collection which includes extension methods on Iterable.
import 'package:collection/collection.dart';
final list = [1, 2, 3];
final x = list.firstWhereOrNull((element) => element > 3);
if (x == null) {
// do stuff...
}
You don't need external package for this instead you can use try/catch
int? x;
try {
x = list.firstWhere((element) => element > 3);
} catch(e) {
x = null;
}
A little bit late but i came up with this:
typedef FirstWhereClosure = bool Function(dynamic);
extension FirstWhere on List {
dynamic frstWhere(FirstWhereClosure closure) {
int index = this.indexWhere(closure);
if (index != -1) {
return this[index];
}
return null;
}
}
Example use:
class Test{
String name;
int code;
Test(code, this.name);
}
Test? test = list.frstWhere(t)=> t.code==123);
An alternative is that you set a nullable type to the list.
Instead of just [1, 2, 3], you write <int?>[1, 2, 3], allowing it to be nullable.
void main() {
final list = <int?>[1, 2, 3];
final x = list.firstWhere(
(element) => element != null ? (element > 3) : false,
orElse: () => null);
print(x);
}
This should work, and it's a better solution:
extension IterableExtensions<T> on Iterable<T> {
T? firstWhereOrNull(bool Function(T element) comparator) {
try {
return firstWhere(comparator);
} on StateError catch (_) {
return null;
}
}
}
To add to #Alex Hartfords answer, and for anyone who doesn't want to import a full package just for this functionality, this is the actual implementation for firstWhereOrNull from the collection package that you can add to your app.
extension FirstWhereExt<T> on List<T> {
/// The first element satisfying [test], or `null` if there are none.
T? firstWhereOrNull(bool Function(T element) test) {
for (final element in this) {
if (test(element)) return element;
}
return null;
}
}
void main() {
const list = [1, 2, 3, 4];
final odd = where(list, (value) => value % 2 == 1);
print(odd);
}
List<T> where<T>(List<T> items, bool Function(T) f) {
var results = <T>[];
for (var item in items) {
if (f(item)) {
results.add(item);
}
}
return results;
}
this kind of error show in my terminal
lib/exercises/18-implement-where-function.dart:3:44: Error: The operator '%' isn't defined for the class 'Object?'.
'Object' is from 'dart:core'.
Try correcting the operator to an existing operator, or defining a '%' operator.
final odd = where(list, (value) => value % 2 == 1);
void main() {
const list = [1, 2, 3, 4];
final odd = where(list, (value) => value! % 2 == 1);
print(odd);
}
List<T> where<T>(List<T> items, bool Function(T) f) {
var results = <T>[];
for (var item in items) {
if (f(item)) {
results.add(item);
}
}
return results;
}
The operator '%' isn't defined for the type 'Object'.
Try defining the operator '%'
Possible Dart analyzer is not able to infer type.
It's better to wait for the answer from the developers.
A workaround as below:
void main() {
const list = [1, 2, 3, 4];
final odd = where(list, (int value) => value % 2 == 1);
print(odd);
}
List<T> where<T>(List<T> items, bool Function(T) f) {
var results = <T>[];
for (var item in items) {
if (f(item)) {
results.add(item);
}
}
return results;
}
P.S.
I also encounter this issue from time to time in Dart.
On the one hand, the type is not explicitly specified (for parameter value) and must be inferred, on the other hand, it is not clear why it is not inferred from another type (aslo T), which is inferred from the value (in our case. list) wuth the same type parameter (T).
I've run your code on https://dartpad.dev/dart, it's working though. I think there is an issue with your import classes.
I need to check whether myItemsList contains myitem.itemId or not, If it exists need to add itemQuantity, if it not exists need to add myitem object to myItemsList.
List<MyItem> myItemsList = new List();
MyItem myitem = new MyItem (
itemId: id,
itemName: name,
itemQuantity: qty,
);
if (myItemsList.contains(myitem.itemId)) {
print('Already exists!');
} else {
print('Added!');
setState(() {
myItemsList.add(myitem);
});
}
MyItem class
class MyItem {
final String itemId;
final String itemName;
int itemQuantity;
MyItem ({
this.itemId,
this.itemName,
this.itemQuantity,
});
}
above code is not working as expected, please help me to figure out the issue.
Contains() compares the whole objects.
Besides overriding == operator or looping over, you can use list's singleWhere method:
if ((myItemsList.singleWhere((it) => it.itemId == myitem.itemId,
orElse: () => null)) != null) {
Edit:
As Dharaneshvar experienced and YoApps mentioned in the comments .singleWhere raises StateError when more elements are found.
This is desired when you expect unique elements such as in the case of comparing IDs.
Raised error is the friend here as it shows that there is something wrong with the data.
For other cases .firstWhere() is the right tool:
if ((myItemsList.firstWhere((it) => it.itemName == myitem.itemName,
orElse: () => null)) != null) {
// EO Edit
Whole example:
List<MyItem> myItemsList = new List();
class MyItem {
final String itemId;
final String itemName;
int itemQuantity;
MyItem({
this.itemId,
this.itemName,
this.itemQuantity,
});
}
void main() {
MyItem myitem = new MyItem(
itemId: "id00",
itemName: "name",
itemQuantity: 50,
);
myItemsList.add(myitem);
String idToCheck = "id00";
if ((myItemsList.singleWhere((it) => it.itemId == idToCheck,
orElse: () => null)) != null) {
print('Already exists!');
} else {
print('Added!');
}
}
As already said before, contains compares two Objects with the == operator. So you currently compare MyItem with String itemId, which will never be the same.
To check whether myItemsList contains myitem.itemId you can use one of the following:
myItemsList.map((item) => item.itemId).contains(myitem.itemId);
or
myItemsList.any((item) => item.itemId == myitem.itemId);
You're using contains slightly wrong.
From: https://api.dartlang.org/stable/2.2.0/dart-core/Iterable/contains.html
bool contains(Object element) {
for (E e in this) {
if (e == element) return true;
}
return false;
}
You can either override the == operator, see: https://dart-lang.github.io/linter/lints/hash_and_equals.html
#override
bool operator ==(Object other) => other is Better && other.value == value;
Or you can loop over your list and search the normal way one by one, which seems slightly easier.
One more way to check does list contain object with property or not
if (myList.firstWhereOrNull((val) => val.id == someItem.id) != null) {}