I've two lists of objects that i wanna compare, a and b:
final dia = DateTime(2017, 9, 7, 17, 30);
final ppp = Parcela("1", 225.5, dia, null, 1, false, false);
final ppp2 =Parcela("1", 225, dia.add(const Duration(days: 3)), null, 1, false, false);
final ppp3 =Parcela("1", 225, dia.add(const Duration(days: 3)), null, 1, false, false);
List<Parcela> a = [ppp,ppp2,];
List<Parcela> b = [ppp, ppp3];
Both of them are equal, but when i try to check it with the functions bellow i get false on response:
print(a.every(b.toSet().contains));
print(listEquals(a, b));
I tried also "quiver" and "collection" libraries from pub dev but the result is the same
The Parcela model:
class Parcela {
String id;
double valor;
DateTime dataPagamento;
DateTime dataPago;
int status;
int ref;
Parcela(String id, double valor, DateTime dataPagamento, DateTime dataPago,
int ref, bool pago, bool atraso) {
this.id = id;
this.valor = valor;
this.dataPagamento = dataPagamento;
this.dataPago = this.dataPago;
this.status = _getStatus(pago, atraso);
this.ref = this.ref;
}
int _getStatus(bool pago, bool atraso) {
if (pago) {
if (atraso) {
return 3;
} else {
return 1;
}
} else {
if (atraso) {
return 2;
} else {
return 0;
}
}
}
}
Edit1:
I've tried Dan James suggestion but my class isn't final as his, so i've removed "final" from name attribute:
class Person extends Equatable {
Person(this.name);
String name;
#override
List<Object> get props => [name];
}
the new test vars:
Person p = Person("name");
Person p2 = Person("name2");
Person p3 = Person("tobias");
List<Person> aa = [p, p2];
List<Person> bb = [p, p2..name = "teste"];
List<Person> cc = [p, p3];
but when i test the lists:
var filtered_lst =List.from(aa.where((value) => !bb.contains(value)));
print(filtered_lst);
print(listEquals(aa, bb));
print(listEquals(aa, cc));
the console returns this:
I/flutter (12746): []
I/flutter (12746): true
I/flutter (12746): false
ppp2 does not equal ppp3 because they are two different instances of a class. You could override the '==' operator to check if each field is the same. ie. ppp2.id == ppp3.id.
eg/ (taken from equatable docs but this is vanillar dart)
class Person {
const Person(this.name);
final String name;
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Person &&
runtimeType == other.runtimeType &&
name == other.name;
#override
int get hashCode => name.hashCode;
}
Or look into the equatable package which does this for you. https://pub.dev/packages/equatable
Straight from the equatable docs:
import 'package:equatable/equatable.dart';
class Person extends Equatable {
const Person(this.name);
final String name;
#override
List<Object> get props => [name];
}
Using the library equatable from Dan James answer:
import 'package:equatable/equatable.dart';
// ignore: must_be_immutable
class Parcela extends Equatable {
String id;
double valor;
DateTime dataPagamento;
DateTime dataPago;
int status;
int ref;
Parcela(String id, double valor, DateTime dataPagamento, DateTime dataPago,
int ref, bool pago, bool atraso) {
this.id = id;
this.valor = valor;
this.dataPagamento = dataPagamento;
this.dataPago = this.dataPago;
this.status = _getStatus(pago, atraso);
this.ref = this.ref;
}
int _getStatus(bool pago, bool atraso) {
if (pago) {
if (atraso) {
return 3;
} else {
return 2;
}
} else {
if (atraso) {
return 1;
} else {
return 0;
}
}
}
#override
List<Object> get props => [id,valor,dataPagamento,];
}
The only way of copying a list that doesn't point to the same memory address:
List<Parcela> copyParcelas(List<Parcela> list) {
List<Parcela> copyList = [];
for (var item in list) {
List<bool> _status = pagoAtraso(item.status);
Parcela betItems = Parcela(item.id, item.valor, item.dataPagamento,
item.dataPago, item.ref, _status[0], _status[1]);
copyList.add(betItems);
}
return copyList;
}
Then the check to return the list items that changed:
List<Parcela> editarParcelas(List<Parcela> parcelas, List<Parcela> original){
return filteredlst = parcelas.toSet().difference(original.toSet()).toList();
}
Related
I am new to riverpod and trying to figure out a state management issue.
I have one list, and two independent states which need access to the list. The states also need to select an element of the list and know what its index is. The list can totally change (add or remove elements) and the states need to determine if their selected element is still in the list and update the index accordingly (to 0 if it is not found)
Here is an example with Riverpod in pure dart:
import 'package:riverpod/riverpod.dart';
void main(List<String> arguments) {
final container = ProviderContainer();
List<String> names = ["Jack", "Adam", "Sally"];
container.read(nameListProvider.notifier).setNames(names);
//selectedName1 = "Adam"
//selectedIndex1 = 1
//selectedName2 = "Sally"
//selectedIndex2 = 2
names.remove('Adam');
container.read(nameListProvider.notifier).setNames(names);
// print(selectedName1) = "Jack" // set to 0 because selection was removed
// print(selectedIndex1) = 0
// print(selectedName2) = "Sally"
// print(selectedIndex2) = 1 // decrement to match Sally's new list index
}
final nameListProvider =
StateNotifierProvider<NameListNotifier, List<String>>((ref) {
return NameListNotifier();
});
class NameListNotifier extends StateNotifier<List<String>> {
NameListNotifier() : super([]);
setNames(List<String> names) {
state = names;
}
}
But I need the selected Name and Index to be Providers
Update: Here is my more elegant solution:
import 'package:riverpod/riverpod.dart';
void main(List<String> arguments) {
final container = ProviderContainer();
List<String> names = ["Jack", "Adam", "Sally"];
print(container.read(nameListProvider));
container.read(nameListProvider.notifier).setNames(names);
var first = container.read(selectionProvider(1).notifier);
first.setName(1);
print(container.read(selectionProvider(1)).name);
var second = container.read(selectionProvider(2).notifier);
second.setName(2);
print(container.read(selectionProvider(2)).name);
names.remove('Adam');
List<String> newNames = List.from(names);
container.read(nameListProvider.notifier).setNames(newNames);
print(container.read(selectionProvider(1)).name);
print(container.read(selectionProvider(1)).index);
print(container.read(selectionProvider(2)).name);
print(container.read(selectionProvider(2)).index);
print(container.read(nameListProvider));
}
final selectionProvider =
StateNotifierProvider.family<SelectionNotifier, Selection, int>(
(ref, page) {
return SelectionNotifier(ref.read);
});
class SelectionNotifier extends StateNotifier<Selection> {
Reader _read;
SelectionNotifier(this._read) : super(Selection());
update() {
final String? selectedName = state.name;
final List<String> names = _read(nameListProvider);
if (names == []) {
state = Selection();
return null;
}
if (selectedName == null) {
state = Selection(name: names[0], index: 0);
return;
}
int i = names.indexOf(selectedName);
if (i == -1) {
state = Selection(name: names[0], index: 0);
return;
}
state = Selection(name: selectedName, index: i);
return;
}
setName(int index) {
final List<String> names = _read(nameListProvider);
state = Selection(name: names[index], index: index);
}
}
final nameListProvider =
StateNotifierProvider<NameListNotifier, List<String>>((ref) {
return NameListNotifier(ref.read);
});
class NameListNotifier extends StateNotifier<List<String>> {
Reader _read;
NameListNotifier(this._read) : super([]);
setNames(List<String> names) {
state = names;
_read(selectionProvider(0).notifier).update();
_read(selectionProvider(1).notifier).update();
}
}
class Selection {
final String? name;
final int? index;
Selection({this.name, this.index});
}
I am trying to get <key,Value> pairs thorugh a single value from values of map.
I am trying to display all the books that have status = true.
But i don't know how can i access status from librarian class(as status is member variable of Book class) and how i can get to the column of status as there are many value for each key.
BOOK CLASS
class Book {
String BookID = '';
String Author ='';
String Name='';
int RackNo=0;
int Price = 0;
bool status = true;
int Edition = 0;
String DateOfPurchase='';
static var count=0;
static var BookList = <String,Object>{};
Book(String BookID , String Author,String Name, int RackNo,int Price, bool status,int Edition,String DateOfPurchase){
this.BookID=BookID;
this.Author=Author;
this.Name=Name;
this.RackNo=RackNo;
this.Price=Price;
this.status=status;
this.Edition=Edition;
this.DateOfPurchase=DateOfPurchase;
BookList[this.BookID]={this.Name, this.Author,this.Name,this.RackNo,this.Price,this.status,this.Edition,this.DateOfPurchase};
count++;
}
void DisplayBookDetails(String ID){
print(BookList[ID]);
}
void UpDateStatus(bool newStatus){
status=newStatus;
}
}
Librarian Class
import 'package:untitled2/Book.dart';
class Librarian {
int count=0;
String Name = '';
String Password = '';
Librarian(String Name,String Password){
this.Name = Name;
this.Password=Password;
}
void SearchBook(String ID){
print(Book.BookList[ID]);
}
void ShowAvailableBooks() {
Book.BookList.values.forEach((element) {print(element);});
}
}
what i am trying to achieve is something like this
if(Book.BookList.values.status==true)//all the books tha have status == true
{
print(Book.BookList[ID's of those books])//display all those books
}
Sorry in advance for poor Question Composition as it is my first time asking a question
Here is an example. I changed your classes around because they were constructed weirdly and you had bookList as a static variable within Book, which wouldn't really work. The main functionality you asked for is in the showAvailableBooks function.
class Book {
final String id;
final String title;
final String? author;
final int? rackNo;
final int? price;
final int? edition;
final String? dateOfPurchase;
bool status;
Book({
required this.id,
required this.title,
this.author,
this.rackNo,
this.price,
this.edition,
this.dateOfPurchase,
this.status = false,
});
void set setStatus(bool newStatus) {
status = newStatus;
}
void printBook() {
print('id: $id, title: $title, author: $author');
}
}
class Librarian {
final String name;
final String password;
Map<String, Book> books = {};
int count = 0;
Librarian({required this.name, required this.password});
void addBooks(List<Book> bookList) {
for (Book book in bookList) {
books[book.id] = book;
count += 1;
}
}
void displayBookDetails(String id) {
books[id]?.printBook();
}
//The function you want
void showAvailableBooks() {
List<String> available = books.keys.where((id) => books[id]!.status == true).toList();
for (String bookID in available) {
books[bookID]?.printBook();
}
}
}
void main() {
Librarian librarian = Librarian(
name: "Mrs. Librarian",
password: "Password123",
);
//Unavailable - status: false
Book book1 = Book(
id: 'abc-123',
title: 'Book 1',
author: 'Author One',
);
//Available - status: true
Book book2 = Book(
id: 'def-456',
title: 'Book 2',
author: 'Author Two',
status: true
);
//Available - status: true
Book book3 = Book(
id: 'ghi-789',
title: 'Book 3',
author: 'Author Three',
status: true
);
librarian.addBooks([book1, book2, book3]);
/*The function you want - prints only books with status: true*/
print('Before changing book1 status to true');
librarian.showAvailableBooks();
book1.setStatus = true;
print('\nAfter changing book1 status to true');
librarian.showAvailableBooks();
}
I've written a class like this,
class LessonCategory{final String name;
LessonCategory(this.name);
#override
String toString() {
return 'LessonCategory{name: $name}';
}
}
class Lessons {
final String lessonsName;
int discontinuity;
final LessonCategory lesscategory;
Lessons(this.lessonsName, this.discontinuity,
this.lesscategory,
);
#override
String toString() {
return 'Lessons{lessonsName: $lessonsName, discontinuity:
$discontinuity, lesscategory: $lesscategory}';
}
}
class Data {
static List<LessonCategory> categories = [
LessonCategory("a1"),
];
static List<Lessons> lessons = [
Lessons(
'Lesson A1',
0,
getCategoryFromName("a1"),
),
];
static LessonCategory getCategoryFromName(name) {
return categories.firstWhere(
(c) => c.name.toLowerCase() == name.toString().toLowerCase());
}
}
But I can't figure out how to add a new element.I already tried add,push,insert (or i missed something).
Can someone please show me the right way?
i want something like
Data.lessons.add({
lessonsName: 'Lesson Z1',
discontinuity: 0
lessCategory: 'a1'
});
just remove static syntax. if it is defined as static, it will be immutable
class Data {
static List<LessonCategory> categories = [
LessonCategory("a1"),
];
List<Lessons> lessons = [ // Remove Static syntax
Lessons(
'Lesson A1',
0,
getCategoryFromName("a1"),
),
];
static LessonCategory getCategoryFromName(name) {
return categories.firstWhere(
(c) => c.name.toLowerCase() == name.toString().toLowerCase());
}
}
but also we can correct another syntaxes
Data newData = Data();
newData.lessons.add(Lessons(
'Lesson Z1', // remove named parameters, and use positional params
0,
LessonCategory('a1'),
));
print("New Length : ${newData.lessons.length}");
Fully working code
class LessonCategory {
final String name;
LessonCategory(this.name);
#override
String toString() {
return 'LessonCategory{name: $name}';
}
}
class Lessons {
final String lessonsName;
int discontinuity;
final LessonCategory lesscategory;
Lessons(
this.lessonsName,
this.discontinuity,
this.lesscategory,
);
#override
String toString() {
return """Lessons{lessonsName: $lessonsName, discontinuity: $discontinuity, lesscategory: $lesscategory}""";
}
}
class Data {
static List<LessonCategory> categories = [
LessonCategory("a1"),
];
List<Lessons> lessons = [ // Remove Static syntax
Lessons(
'Lesson A1',
0,
getCategoryFromName("a1"),
),
];
static LessonCategory getCategoryFromName(name) {
return categories.firstWhere(
(c) => c.name.toLowerCase() == name.toString().toLowerCase());
}
#override
String toString() {
return "{${lessons.map((fruit) => print(fruit))}}";
}
}
main(List<String> args) {
Data newData = Data(); // Create instance first
newData.lessons.add(Lessons(
'Lesson Z1', // remove named parameters, and use positional params
0,
LessonCategory('a1'),
));
print("New Length : ${newData.lessons.length}");
newData.lessons.add(Lessons(
'Lesson Z1',
0,
LessonCategory('a1'),
));
print("New Length : ${newData.lessons.length}");
print("${newData.lessons}");
}
which we able to play arount in Dartpad
Result
remove the static syntax and the problem will be solved
I wanted to display contact which has id = 'asdf-123' from List of class Contact which have attributes [id, name, phone, dob].
i can do it by doing
bool isContainId = false;
String testId = 'asdf-123';
contacts.foreach((contact) {
if (contact.id == testId) {
isContainId = true;
}
});
however, is there any better way of doing it. something like .contains. please help!.
Contains can not work with custom models in dart, you have to traverse through each object for this kind of operation.
bool isContainId = false;
String testId = 'asdf-123';
isContainId = contacts.firstWhere((contact)=> contact.id == testId, orElse: (){isContainId = false;}) != null;
UPDATE:
class CustomModel {
int id;
CustomModel({this.id});
}
void main() {
List<CustomModel> all = [];
for (var i = 0; i < 4; i++) {
all.add(CustomModel(id: i));
}
bool isContainId = false;
isContainId = all.firstWhere((contact)=> contact.id == 5, orElse: (){isContainId = false;}) != null;
print(isContainId);
}
I am using JPA / Eclipselink / PostgreSQL within my application.
I have a model that list some data, and I would like to let the user of the application to create his own where clause parameters.
How can I store theses parameters ? as plain sql string ?
Then how can I apply the where clause ? as a simple string concatenation ? (I don't like this idea at all).
Bests regards.
Ok, so I solved my problem.
For information : I have created a recursive JSON representation of every where clause parameters possibility.
And I have created a query using criteria api by decoding the pojo structure from json.
The json class look like that :
public class JSonSearchCriteria
{
public static enum CriteriaType
{
asc,
desc,
count,
countDistinct,
and,
or,
not,
equal,
notEqual,
between,
gt,
ge,
lt,
le,
like,
notLike;
}
#Expose
public CriteriaType type;
#Expose
public List<JSonSearchCriteria> sub;
#Expose
public String what = null;
#Expose
public List<Integer> integerValue = null;
#Expose
public List<Long> longValue = null;
#Expose
public List<Boolean> booleanValue = null;
#Expose
public List<String> stringValue = null;
#Expose
public List<DateTime> datetimeValue = null;
public JSonSearchCriteria()
{
}
public JSonSearchCriteria(final CriteriaType type)
{
this.type = type;
}
public JSonSearchCriteria(final CriteriaType type, final String what)
{
this(type);
this.what = what;
}
public JSonSearchCriteria(final CriteriaType type, final String what, final String... values)
{
this(type, what);
for(final String value : values)
{
value(value);
}
}
public JSonSearchCriteria(final CriteriaType type, final String what, final Long... values)
{
this(type, what);
for(final Long value : values)
{
value(value);
}
}
public JSonSearchCriteria(final CriteriaType type, final String what, final Integer... values)
{
this(type, what);
for(final Integer value : values)
{
value(value);
}
}
public JSonSearchCriteria(final CriteriaType type, final String what, final DateTime... values)
{
this(type, what);
for(final DateTime value : values)
{
value(value);
}
}
public void add(final JSonSearchCriteria subCriteria)
{
if(sub == null)
{
sub = new ArrayList<>();
}
sub.add(subCriteria);
}
public void value(final String value)
{
if(stringValue == null)
{
stringValue = new ArrayList<>();
}
stringValue.add(value);
}
public void value(final Long value)
{
if(longValue == null)
{
longValue = new ArrayList<>();
}
longValue.add(value);
}
public void value(final Integer value)
{
if(integerValue == null)
{
integerValue = new ArrayList<>();
}
integerValue.add(value);
}
public void value(final DateTime value)
{
if(datetimeValue == null)
{
datetimeValue = new ArrayList<>();
}
datetimeValue.add(value);
}
#SuppressWarnings(
{
"unchecked", "rawtypes"
})
#Transient
public Predicate buildPredicate(final CriteriaBuilder builder, final Root<Record> root, Join<Record, RecordInfo> infos)
{
switch(type)
{
case and:
case or:
final Predicate[] preds = new Predicate[sub.size()];
int cpt = 0;
for(final JSonSearchCriteria s : sub)
{
preds[cpt] = s.buildPredicate(builder, root, infos);
cpt++;
}
if(type == CriteriaType.and)
{
return builder.and(preds);
}
else if(type == CriteriaType.or)
{
return builder.or(preds);
}
break;
case equal:
case lt:
case gt:
case between:
final Path p;
if(what.startsWith("infos."))
{
p = infos.get(what.substring(6));
}
else
{
p = root.get(what);
}
if(stringValue != null && !stringValue.isEmpty())
{
if(type == CriteriaType.equal)
{
return builder.equal(p, stringValue.get(0));
}
}
else if(longValue != null && !longValue.isEmpty())
{
if(type == CriteriaType.equal)
{
return builder.equal(p, longValue.get(0));
}
else if(type == CriteriaType.lt)
{
return builder.lt(p, longValue.get(0));
}
else if(type == CriteriaType.gt)
{
return builder.gt(p, longValue.get(0));
}
}
else if(integerValue != null && !integerValue.isEmpty())
{
if(type == CriteriaType.equal)
{
return builder.equal(p, integerValue.get(0));
}
else if(type == CriteriaType.lt)
{
return builder.lt(p, integerValue.get(0));
}
else if(type == CriteriaType.gt)
{
return builder.gt(p, integerValue.get(0));
}
}
else if(booleanValue != null && !booleanValue.isEmpty())
{
return builder.equal(p, booleanValue.get(0));
}
else if(datetimeValue != null && !datetimeValue.isEmpty())
{
if(type == CriteriaType.equal)
{
return builder.equal(p, datetimeValue.get(0));
}
else if(type == CriteriaType.between && datetimeValue.size() > 1)
{
return builder.between(p, datetimeValue.get(0), datetimeValue.get(1));
}
}
break;
}
System.err.println(type + " - not implemented");
return null;
}
}
And it is used like that :
final SearchTemplate templ = DBHelper.get(SearchTemplate.class, 100);
final Gson gson = new GsonBuilder().registerTypeAdapter(DateTime.class, new DateTimeJsonAdapter()).create();
final JSonSearchCriteria crits = gson.fromJson(templ.getTemplate(), JSonSearchCriteria.class);
final CriteriaBuilder critBuilder = DBHelper.getInstance().em().getCriteriaBuilder();
final CriteriaQuery<Record> critQuery = critBuilder.createQuery(Record.class);
final Root<Record> root = critQuery.from(Record.class);
final Join<Record, RecordInfo> infos = root.join("infos");
critQuery.where(crits.buildPredicate(critBuilder, root, infos));
final TypedQuery<Record> query = DBHelper.getInstance().em().createQuery(critQuery);
final List<Record> result = query.getResultList();
for(final Record rec : result)
{
System.err.println(rec.toString());
}