Creating and changing existent Methods for Dart classes - dart

I'm trying to program with Dart on Visual Studio Code and need to understand the Syntax of Dart a bit more to be able to code what is needed.
These are the classes I have coded:
Book (defines book title, isbn, price and availability)
class Book {
// properties
late String _title;
late int _isbn;
late double _price;
bool _isAvailable;
....
}
BookCatalog (imports prior class and defines current list of books + methods to add new books)
class BookCatalog{
// no arrays, everything is a list
List<Book> _books = [];
...
}
Main (imports prior classes and executes wanted input)
What I want to change:
improve addBook Method within BookCatalog Class, to not add a new Book, if it has the same ISBN as a already existing one, which it currently does. (Potentially give out message stating 'false' if user tries to add Book with same ISBN)
// adds a book to the store
void addBook(book) {
_books.add(book);
}
improve printBookCatalog Method within BookCatalog Class, to only print available Books and not all Books added to the Store.
// Print books contained in the catalog
void printBookCatalog() {
print("List of Books:");
for (var book in _books) {
print(book);
}
}
improve getBook Method within BookCatalog Class, to actually get the book by its ID, as it's not working right now.
// Get a book by id
Book getBook(int place) => _books[place];
improve calculateAvgPrice Method within BookCatalog Class, to calculate the average price of Books, it's not working correctly as of now
// NEW, calculates average price of books
Book calculateAvgPrice(double price) {
for(var book in _books) {
sum += book.Price;
}
return sum / _books.length;
}
create a new Method within BookCatalog Class to delete Books from the Catalog
answer could be, but I'm not sure :
// deletes book from the catalog
void deleteBook(book) {
_books.remove(book);
}
Any help, explanations, examples or external sources to read up on Dart would be appreciated!
(Especially examples for my specific cases)

I suggest going through Dart Language Tour first.
(Side note: ISBN has leading zero and hyphen, so it's better to use a String for it instead of int)
In your BookCatalog class, you could use a Map instead of a List:
class BookCatalog {
Map<String, Book> _books = {}; // Map from ISBN to Book
// ...
}
Here I'm assuming that both classes are in the same file, otherwise accessing private members wouldn't work, so you'd have to have public getters available.
/// Adds a book to the store only if the ISBN does NOT exist.
bool addBook(Book book) {
if (_books.containsKey(book._isbn)) {
return false;
}
_books[book._isbn] = book;
return true;
}
Missing the if conditional.
void printBookCatalog() {
print("List of Books:");
for (final book in _books.values) {
if (book._isAvailable) {
print(book);
}
}
}
Assuming that by id you mean, its ISBN. It returns a nullable Book? because the isbn might not exist in the catalog.
// Get a book by id
Book? getBook(String isbn) => _books[isbn];
The function has a return type of double not a Book as it's the average price. You also don't need to provide any argument to this function. And you need to define the sum variable first before using it!
double calculateAvgPrice() {
var sum = 0.0;
for (final book in _books.values) {
sum += book._price;
}
return sum / _books.length;
}
Assuming that you want to remove books by their ISBN:
bool removeBook(String isbn) {
return _books.remove(isbn) != null;
}

Related

How to clone (copy values) a complex object in Dart 2

I would like to clone a complex object (copy values), not referencing, using Dart 2.
Example:
class Person {
String name;
String surname;
City city;
}
class City {
String name;
String state;
}
main List<String> args {
City c1 = new City()..name = 'Blum'..state = 'SC';
Person p1 = new Person()..name = 'John'..surname = 'Xuebl'..city = c1;
Person p2 = // HERE, to clone/copy values... Something similar to p1.clone();
}
What would be the way (best practice) to do this?
Update note: This How can I clone an Object (deep copy) in Dart? was posted some time ago. The focus here is to understand if Dart 2 that is bringing many improvements, has a facility for copying complex objects.
With the classes you have shown us here, there is nothing shorter than
Person p2 = Person()
..name = p1.name
..surname = p1.surname
..city = (City()..name = p1.city.name..state = p1.city.state);
If you add a clone method to Person and City, then you can obviously use that.
There is nothing built in to the language to allow you to copy the state of an object.
I would recommend changing the classes, at least by adding a constructor:
class Person {
String name;
String surname;
City city;
Person(this.name, this.surname, this.city);
}
class City {
String name;
String state;
City(this.name, this.state);
}
Then you can clone by just writing:
Person P2 = Person(p1.name, p1.surname, City(p1.city.name, p1.city.state));
(And ob-link about names)
I say that there is no language feature to copy objects, but there actually is, if you have access to the dart:isolate library: Sending the object over a isolate communication port. I cannot recommend using that feature, but it's here for completeness:
import "dart:isolate";
Future<T> clone<T>(T object) {
var c = Completer<T>();
var port = RawReceivePort();
port.handler = (Object o) {
port.close();
c.complete(o);
}
return c.future;
}
Again, I cannot recommend using this approach.
It would work for simple objects like this, but it doesn't work for all objects (not all objects can be sent over a communication port, e.g., first-class functions or any object containing a first class function).
Write your classes to support the operations you need on them, that includes copying.
My simpler solution just let clone() return a new Person with the current values:
class Person {
String name;
String surname;
City city;
Person(this.name, this.surname, this.city);
clone() => Person(name, surname, city);
}
You might further need to recursively clone the objects in your Person. as an example by creating a similar clone() function in the City and using it here as city.clone().
For the strings you will need to check their behavior or also create / add a way for cleaning them.
As said, there is no built in solution for that, but if the ideia is to accomplish immutable value types you can check built_value.
https://medium.com/dartlang/darts-built-value-for-immutable-object-models-83e2497922d4
I noted that using Map.from() do a shallow copy and not a deep copy.
To do a deep copy of a class containing a Map of anoter Class, one solution can be to use a nammed constructor
class MyClassB {
int myVar;
// Constructor
MyClassB(this.id);
// Named Constructor to do a deep clone
MyClassB.clone(MyClassB b){
id = b.id;
}
}
class MyClassA {
Map<int,MyClassB> mapOfClassB;
// Constructor
MyClassA(this.myClassB)
// Named constructor to do a deep clone
MyClassA.clone(MyClassA a){
Map<int,myClassB> m = {};
myClassB = a.mapOfClassB.forEach((k,v)=> m[k] = MyClassB.clone(v)); // Use the clone constructor here, if not the maps in MyClassA and MyClassB will be linked
}
}
main() {
var b1 = MyClassB(20);
var a1 = MyClassA({0:b1});
var a2 = MyClass1A.clone(a1);
a2.mapOfClassB[0].id = 50;
print(a1.mapOfClassB[0].id); // Should display 20
print(a2.(a1.mapOfClassB[0].id) // Should display 50
}
Using a package like freezed, you could make deep copies of the complex objects.
Although one downside is that the objects are immutable and you cannot make shallow copies of it. But again, it depends on your use case and how you want your objects to be.

How can I get objects based off of certain associations?

I have the following domain classes (Only trying to show what is needed to get the idea) :
class Scholarship {
static hasMany = [grades:Grade]
}
and
class Grade {
String id
String description
}
In words I would like to, "Get all scholarships where the associated grade_id = myId". I would like to accomplish this using grails domain classes and not using sql. Any help appreciated
Are you looking for something like this?...
def results = Scholarship.withCriteria {
grades {
// myId must be defined somewhere above...
idEq myId
}
}
EDIT
A comment below adds to the original question and asks what if another relationship was expressed like this...
class Scholarship {
static hasMany = [grades:Grade,majors:Major]
}
The query I show above would still be exactly the same. The fact that there is a majors collection would not be relevant unless you wanted to include some attribute of Major to also be part of the criteria, which could look something like this...
def results = Scholarship.withCriteria {
grades {
// myId must be defined somewhere above...
idEq myId
}
majors {
// only return Scholarship instances which
// contain a Major with the name 'Mechanical Engineering'
eq 'name', 'Mechanical Engineering'
}
}
I hope that helps.

Grails - List of Long not getting saved

I have a domain class similar to the following:
class Record {
Long id
List numbers = []
String description
void recordNumber(Long number) {
//requirements, validations, etc.
numbers << number
}
}
Then I defined a Web service similar to the code below:
class RecordController extends RestfulController {
def recordNumber(Record record) {
def number = getNumberFromRequest() //request.JSON, request.XML, etc.
if (record) {
record.recordNumber(number)
record.save(flush: true, failOnError: true)
}
}
}
However, the numbers on the list don't seem to get saved, because when I retrieve a Record, the list empty. I have test for the code and it seems ok. Could it also be that the list is lazily loaded?
You are saving a new record instance each time the action is called. You should load it out of the DB instead:
def recordNumber( Long id ){
def record = Record.get id
def number = getNumberFromRequest() //request.JSON, request.XML, etc.
//....
}
So based on this answer from a previous StackOverflow question, I updated the code as follows:
class Record {
static hasMany = [numbers: Long]
Long id
String description
void recordNumber(Long number) {
//requirements, validations, etc.
addToNumbers number
}
}
It would seem that if a collection is meant to be persistent, it has to be declared this way, or be mapped in some other methods; I'm just not sure what those other methods are.

grails unknown number of model objects in the view

Working in Grails 2.2
I have a situation where I need to be able to handle an unknown number of CommitteeMembers in the view. These need to be both created and displayed.
Each one has the usual attributes - name, address, contact information, userid.
I understand that if I name form fields the same name, Grails will return a collection for me to iterate over. In this case, however, I am faced with this situation:
cm_firstname
cm_lastname
cm_address
cm_email
cm_userid
So does this mean I will be given collections of each of these fields? That is not as useful as there is no way to corelate the various firstnames with the correct lastnames, etc.
I am enjoying Grails and am looking forward to your feedback.
You can use Grails Command objects to do this work for you. Here's an example in a SO question. Basically you will have a single collection of CommitteeMembers that will be populated in your controller thorugh data binding.
As #Gregg says, in the view you need the fields to have an index.
class MyDomain {
String name
}
class MyDomainCommand {
List<MyDomain> instances = ListUtils.lazyList([], FactoryUtils.instantiateFactory(MyDomain))
}
class MyController {
def save() {
MyDomainCommand command = new MyDomainCommand()
bindData(command, params, [include: 'instances'])
}
}
I'll tell you what I do, which may or may not be the best option. I do this mainly because I don't like data binding.
For your case as an example, I would name my fields: "cm.firstName, cm.lastName, cm.address, cm.email, cm.userId".
If you are in a service:
GrailsWebRequest webUtils = WebUtils.retrieveGrailsWebRequest()
List committeeMembers = [].withDefault {new GrailsParameterMap([:], webUtils.getCurrentRequest())}
In a controller:
List committeeMembers = [].withDefault {new GrailsParameterMap([:], request)}
Then
params.cm.each { k, v ->
if (v instanceof String[]) {
v.eachWithIndex { val, idx ->
committeeMembers[idx]."$k" = val
}
}
else {
committeeMembers[0]."$k" = v
}
}
Then you can do:
committeeMembers.each {
<Create from it.firstName, it.lastName, etc>
}

Finding The Super Class of a class just before Top Class with Jena

I am using jena framework to process my owl ontology.
I want to write a method which can find the super class it belongs which is just under the Thing class.
Four example, if there are 5 level hierarchy, lets say first level is Thing, second level is secondAncestor, third level is ThirdAncestor and so on. If I pass a class FifthAncestor, I want to return SecondAncestor because Thing does not make any sense. If I pass ThirdAncestor, I want to return SecondAncestor. In other words, most general class it belongs to but not the top one (Thing).
Method one
This will depend on your model having a reasoner, because owl:Thing isn't normally asserted into a model, and so won't be present in a model with no reasoner. Given that, then:
OntModel m = ... your OntModel ...;
OntClass thing = m.getOntClass( OWL.Thing.getURI() );
for (Iterator<OntClass> i = thing.listSubClasses(true); i.hasNext(); ) {
OntClass hierarchyRoot = i.next();
....
}
Note the use of the flag direct = true in the listSubClasses() call.
Method two
Does not require a reasoner.
for (Iterator<OntClass> i = m.listHierarchyRootClasses(); i.hasNext(); ) {
OntClass hierarchyRoot = i.next();
....
}
Note that this method will return the root classes, even if they are anonymous resources representing a class expression. For UI purposes, this often isn't what you want (it's hard to display a bNode in a meaningful way to a user). In this case, use OntTools.namedHierarchyRoots instead.
Update
I now understand that Alan wants the root classes that are parents of a particular class, whereas namedHierarchyRoots will list all of the root classes of the class hierarchy. Note that, in general, a class may have zero, one or many named-superclasses between it and Thing.
Anyway, here's how I would solve this. Again, this solution assumes the model is not using a reasoner. With a reasoner, it would be much easier:
private boolean hasSubClassTransitive( OntClass parent, OntClass child ) {
return OntTools.findShortestPath( child.getOntModel(), child, parent,
new OntTools.PredicateFilter( RDFS.subClassOf ) ) != null;
}
public List<OntClass> namedRootsOf( OntClass c ) {
List<OntClass> cRoots = new ArrayList<OntClass>();
for (OntClass root: OntTools.namedHierarchyRoots( c.getOntModel() )) {
if (hasSubClassTransitive( root, c )) {
cRoots.add( root );
}
}
return cRoots;
}
I find solution in following way without using reasoner. It is not perfect solution but it works. This solution also solves problem, if you get unnamed (anonymous) class as super class.
First I created an array which stores top level class names.
A simple method which searches in my created array, if the passed parameter is a top class.
public Boolean IsTopClass(String ontologyClass)
{
//NS is URI of ontology
String onClass=ontologyClass.replace(NS, "");
for(String oClass: topLevelClassList)
{
if(oClass.equalsIgnoreCase(onClass))
return true;
}
return false;
}
Then the main method which finds most general class under thing:
public String FindSuperClassUnderThing(OntClass subClass)
{
OntClass prevSubClass=subClass;
OntClass prevprevSubClass=null;
String topClass="";
String supClass=subClass.toString();
ExtendedIterator<OntClass> superClassList=null;
while(!this.IsTopClass(topClass))
{
prevprevSubClass=prevSubClass;
prevSubClass=prevSubClass.getSuperClass();
//if returned class is a anonymous class (not a named one)
//get list of superclasses and check if there is a topclass
//inside the super class list
if(!prevSubClass.toString().startsWith(NS))
{
prevSubClass=prevprevSubClass;
superClassList= prevSubClass.listSuperClasses();
while(superClassList.hasNext())
{
OntClass OntClassFromList= superClassList.next();
if(this.IsTopClass(OntClassFromList.toString()))
{
topClass= OntClassFromList.toString();
}
}
}
else
{
if (this.IsTopClass(prevSubClass.toString()))
{
topClass= prevSubClass.toString();
}
}
}
return topClass;
}

Resources