I have a huge problem with my code:
public class BookStore
{
private ArrayList<Book> books;
}
/**
* This method takes the author's name as a String parameter and returns an
* arraylist of all the books written by that author. It uses a while loop
* and an iterator, locates the books written by that author (case-insensitive)
* and adds them to another arraylist.
*/
public ArrayList<Book> getBooksByAuthor(String authorName){
ArrayList<Book> getBooksByAuthor = new ArrayList<Book>();
Iterator<Book> aBook = books.iterator();
while(aBook.hasNext()){
Book aBookd = aBook.next();
if (authorName.equalsIgnoreCase(aBookd.getAuthor())){
books.add(getAuthor());
books.addAll(getBooksByAuthor);
}
}
return getBooksByAuthor.size();
}
Those 3 lines
books.add(getAuthor());
books.addAll(getBooksByAuthor); and the
return getBooksByAuthor.size();
I'm pretty sure that they are completely wrong. I tried different ways to do it ,but it didn't work. I really don't understand how to do that. Could someone help me?. Thank you for your time!
I'm fairly certain you wanted to add the book(s) with matching author's name to a new List. Something with an implicit iterator using a for-each loop
List<Book> al = new ArrayList<>();
for (Book book : books) {
if (authorName.equalsIgnoreCase(book.getAuthor())) {
al.add(book);
}
}
return al;
or using an explicit Iterator like
List<Book> al = new ArrayList<>();
Iterator<Book> iter = books.iterator();
while (iter.hasNext()) {
Book book = iter.next();
if (authorName.equalsIgnoreCase(book.getAuthor())) {
al.add(book);
}
}
return al;
is there any specific need for the iterator and a while-loop instead of a foreach loop?
what (i think) you'd like to achive is in normal language is: we have an empty collection/list as result. for each book in the list of books, check if the author has an equal name to the given name - if the names are equal, we add the book to the resulting collection/list.
that in code looks like:
public ArrayList<String> getBooksByAuthor(String authorName) {
ArrayList<Book> result = new ArrayList<Book>();
for (Book aBook : books) { //[for each notation in java ][1]
if (authorName.equals(aBook.getAuthor())) {
result.add(aBook);
}
}
return result;
}
if you'd like to use a while loop, read up the foreach/while loop conversion in the this link.
in addition and as mentioned in the comments, your code has some semantic and syntactic errors:
your return type is wrong (int instead of ArrayList)
your class definition closing brace ends before your method definition
you add the author object (probably a string) to your books-collection
you never add any book to your resulting collection
you try to addAll objects of your (empty) collection getBooksByAuthor to your books, instead of adding some/single books to your getBooksByAuthor collection
[1] http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
Related
I've been stuck on this question in an assignment in which I must "List the stations along a given subway line"
There are two Hash Maps:
private Map<String, Station> allStations = new HashMap<String, Station>(); // all stations, indexed by station name
private Map<String, SubwayLine> allSubwayLines = new HashMap<String, SubwayLine>(); // all subway lines, indexed by name of the line
I am trying to call the "getStations()" method, which is a part of the subwayLine class:
public List<Station> getStations(){
return Collections.unmodifiableList(stations);
}
On a subwayLine object which is linked to a button:
public void listStationsOnLine(){
UI.clearText();
List<SubwayLine> subwayLines = new ArrayList(allSubwayLines.values());
for(SubwayLine s : subwayLines){
s.getStations();
}
}
However, this does nothing. Is there anyway in which I can return the stations along the given subwayLine?
you have to save your data in an arraylist again :
public void listStationsOnLine(){
UI.clearText();
List<SubwayLine> subwayLines = new ArrayList(allSubwayLines.values());
List<Collection<Station>> stations = new ArrayList();
for(SubwayLine s : subwayLines){
stations.add(s.getStations());
}
}
The void keyword in your method means that it does not return anything.
You might want to replace it with List and return it at the end of your method, like
public List<Station> listStationsOnLine(){
UI.clearText();
List<SubwayLine> subwayLines = new ArrayList(allSubwayLines.values());
List<Collection<Station>> stations = new ArrayList<>();
for(SubwayLine s : subwayLines){
stations.add(s.getStations());
}
return stations
}
Please note that you loop through all subwaylines and therefore your stations arraylist consists of all stations that are along some subwayline. So not a list of stations per subwayline. Also, I added a diamond operator to the arraylist call. That will automatically make an ArrayList of the type Collection<Station>. However, making a List of Collections seems not right here? You probably just want a List of <Station>.
Moreover, the call s.getStations() seems to yield all stations at subwayLine s? The description of your question seems to ask how to implement thát method.
In your question, you seem to prefer a list of stations for a given subwayline. That should then be input for your method, something like this:
public List<Station> listStationsOnLine(SubwayLine subwayline){
UI.clearText();
List<Station> allStations = getStations();
List<Station> stations = new ArrayList<>();
for(Station s : allStations){
if(s.onLine(subwayline)) {
stations.add(s);
}
}
return stations
}
Arraylist<Books> booksdtoList=new ArrayList<>();
List<Object[]> modelList =null;
modellist=repostory.getbooks("FICTION");
booksdtoList =mapdto(booksdtoList,modellist);
modellist=repostory.getbooks("COMIC");
booksdtoList =mapdto(booksdtoList,modellist);
Arraylist<Books> booksdtoList mapDto(Arraylist<Books> booksdtoList, List<Object[]> modelList){
Books books=null;
for (model:modelList){
books=new Books((String)model[0],(String)model[1]));
booksdtoList.add(books);
}
return booksdtoList;
}
Will booksdtoList contain all the list of books or will it override any object within list?
Is it best practice to send ArrayList as argument and add? If not please suggest best one.
I can't say really what is best practice but I would probably instantiate the List in the mapping method if it is always expected to be empty before calling it:
List<Books> mapDTO(List<Object[]> modelList) {
List<Books> booksDTOList = new ArrayList<>();
Books books = null;
for (Object[] model : modelList){
books = new Books((String)model[0], (String)model[1]);
booksDTOList.add(books);
}
return booksDTOList;
}
Note also that it's best to use the List interface for the object.
To collect all books from multiple calls:
List<Books> booksDTOList=new ArrayList<>();
// ....
booksDTOList.addall(mapDTO(modelList1));
booksDTOList.addall(mapDTO(modelList2));
booksDTOList.addall(mapDTO(modelList3));
If you do choose to pass the list to the mapping method, you don't need to return it since Java is pass by reference (the list object that is inside the mapping method is the same object instance as in the caller).
void mapDTO(Arraylist<Books> booksDTOList, List<Object[]> modelList){
Books books = null;
for (Object[] model : modelList){
books = new Books((String)model[0], (String)model[1]);
booksDTOList.add(books);
}
}
To answer your first question, adding objects to a List (ArrayList or otherwise) will not overwrite already existing elements in the list.
Edit I updated all examples with camelCase method and object names (and corrected some syntax errors).
One more change you could do (based on the information available) is to change the modelList to contain String arrays:
void mapDTO(Arraylist<Books> booksDTOList, List<String[]> modelList){
Books books = null;
for (String[] model : modelList){
books = new Books(model[0], model[1]);
booksDTOList.add(books);
}
}
Here I have created a class:
class book{
String book_nm;
String author_nm;
String publication;
int price;
book(String book_nm,String author_nm,String publication,int price){
this.book_nm=book_nm;
this.author_nm=author_nm;
this.publication=publication;
this.price=price;
}
}
Now I want to search for particular value according to author and book name
ArrayList<book> bk = new ArrayList<book>();
I have created a menu driver using switch case
case 3: System.out.println("Search:"+"\n"+"1.By Book Name\n2.By Author Name");
Scanner s= new Scanner(System.in);
int choice=s.nextInt();
while(choice<3){
switch(choice){
case 1:System.out.println("Enter the name of the book\n");
String name=s.next();
-------
case 2:System.out.println("Enter the name of the author\n");
String name=s.next(); ------
}
}
I know how to find and search for a particular element in ArrayList but not for objects.
Using for loop over ArrayList can solve your problem, it's naive method and old fashioned.
Below is the code for it.
import java.util.ArrayList;
public class HelloWorld{
public static void main(String []args){
String author_name = "abc";
ArrayList<book> bk = new ArrayList<book>();
bk.add(new book("abc", "abc", "abc", 10));
bk.add(new book("mno", "mno", "abc", 10));
bk.add(new book("xyz", "abc", "abc", 10));
ArrayList<book> booksByAuthor = new ArrayList<book>();
for(book obj : bk)
{
if(obj.author_nm == author_name)
{
booksByAuthor.add(obj);
}
}
}
}
class book{
public String book_nm;
public String author_nm;
public String publication;
public int price;
public book(String book_nm,String author_nm,String publication,int price){
this.book_nm=book_nm;
this.author_nm=author_nm;
this.publication=publication;
this.price=price;
}
}
Hope you can get an idea from it.
Below code return a list, based on of your search (filter):
List< Book> result = bk.stream().filter(book -> "booknamehere".equals(book.getBook_nm()))
.filter(book -> "authernamehere".equals(book.getAuther_nm()))
.collect(Collectors.toList());
First there is a new ways (With java 8+) and old way to do this. The new ways will be something like this:
String authorName = s.next();
String bookName = s.next();
List<String> result = bk.stream() // open stream
.filter(book-> book.getBook_nm().equals(bookName) && book.getAuthor_nm().equals(authorName ) )
.collect(Collectors.toList());
Another (old fashioned) way is with for loop:
ArrayList<book> result = new ArrayList<book>();
for(Book book : bk) //By the way always use Big first letter for name of your Class! (Not book but Book)
{
if(book.getBook_nm().equals(bookName) && book.getAuthor_nm().equals(authorName))
{
result.add(book);
}
}
After this you can print in both cases the result list containing the book. But if you will search a lot of this author and book name and you have a lots of elements you can think check the performance. Because every search will loop over the list. Maybe there is better solution using Map ...
Some additional information. It is import if you know if there is always only one element that will be found from the criteria. For example in your case you unique find one book where has name X and author Y. There can not be another book with the same name and author. In such cases you can do like this:
New way (after java 8):
Book res = bk.stream()
.filter(book -> book.getBook_nm().equals(bookName) && book.getAuthor_nm().equals(authorName))
.findFirst()
.get();
old way:
Book result = null;
for(Book book : bk)
{
if(book.getBook_nm().equals(bookName) && book.getAuthor_nm().equals(authorName))
{
result = book;
break;
}
}
This way it is faster when you search one element
Good luck!
I am trying to display the lists of genre in the genre type that I have in the linked list. I did:
public void outputGenre(){
booksAvilable = new LinkedList <Book>();
booksAvailable.add(new book("Enders Game",1999,new Genre ("SciFi"),3));
booksAvailable.add(new book("Star Trek",1974,new Genre ("SciFi"),4));
booksAvailable.add(new book("Game of Thrones",1991,new Genre ("Drama"),3));
System.out.println("We have following Genres");
for(Book books:booksAvilable()){
Genre genre = books.getGenre();
System.out.println(genre);
}
}
This code outputs SciFi twice and Drama once. I want to make it display SciFi only once. I thought of using counter and if/else statements, but I got lost.
Because you asked for a version without streams, though I cannot imagine why:
Set<Genre> seen = new HashSet<>();
for(Book books:booksAvailable() ){
Genre genre = books.getGenre();
if (!seen.contains(genre)) {
System.out.println(genre);
seen.add(genre);
}
}
In this case you need to maintain a record of which genres you already have seen and only display it if not yet seen.
It doesn't take much arguing that the streaming variant is cleaner and more concise.
Still requires an implementation of equals to function correctly, and because I used a HashSet also a int hashCode(), which simply can return the hashcode of the genre's name string.
Yet another form is recording the names of the genres in a set, requiring two loops:
Set<String> genres = new HashSet<>();
for(Book books:booksAvailable() ){
Genre genre = books.getGenre();
genres.add(genre.getName());
}
for(String genre : genres) {
System.out.println(genre);
}
I'd still go for the stream solution, personally.
You can use Java streams:
booksAvailable.stream().map(Book::getGenre).distinct().forEach(System.out::println)
Assuming you have an equals method in your Genre class, otherwise it can't determine the distinct cases of a genre.
Im using arraydeque to create list of items and pass them parameters(Items is class)
ArrayDeque<Item> Items= new ArrayDeque<Item>();
But I have problem with java ArrayDeque. Maybe there are ways to add more than one element at once.
For example. I want add at the same time TableType and colourOfTable into ArrayDeque.
In c++ I could have done it with this
vector<Item>Items
Items.push_back(Item("CoffeeTable", "brown"));
I want to do the same thing with Java. Instead of creating a new obj for every item, as:
ArrayDeque<Item> Items = new ArrayDeque<Item>();
Item obj = new Item("CoffeTable", "brown");
Items.add(obj);
Item obj1 = new Item("DinnerTable", "Black");
Items.add(obj1);
But instead of obj I want to add "CoffeTable", "brown" at the same time and with one code line (like in c++ example) into the Items array.
I tried something like that
ArrayDeque<Item> Items= new ArrayDeque<Item>();
Items.add(Items("CoffeTable", "brown"));
But then got the error while creating create method 'Items(String,String)'
You can simple create the new item in the call of add:
items.add(new Item("CoffeTable", "brown"));
So you don't need an explicit variable.
Also note that in Java variable names normally start with a lower case character.
You will have to create a new object anyway to hold these 2 values.
You can do this:
Items.add(new Item("CoffeTable", "brown"));
Anything else you come up with will be syntactic sugar for the above
For example: you can add a static method to your class:
public static Item item(String k1, String k2) {
return new Item(k1, k2);
}
And use it later:
Items.add(item("CoffeTable", "Brown"));
Here is a solution which would surely work. You can add a function to your class itemAdd() as follows:
class Samp {
public static void main(String args[]){
//code.....
ArrayDeque<Item> Items= new ArrayDeque<Item>();
Items.add(itemAdd("CoffeeTable", "brown"));
//rest of code....
}
public static Item itemAdd(String tableType,String colourOfTable){
return new Item(tableType,colourOfTable);
}
}
class Item{
String tableType;
String colourOfTable;
Item(String tableType,String colourOfTable ){
this.tableType=tableType;
this.colourOfTable=colourOfTable;
}
}
Its similar to what u need to do!! Best of luck :)