Replacing ArrayLists with HashMaps - java

I am currently working on a project where I am replacing the ArrayLists in my code with HashMaps and I've run into a problem. In this section of my code I am creating a new "Book" from my book class and in the "get book" section is where I am having the problem. I am trying to check the (now)HashMap books to see if the book ID from the getId() method match the bookID of the book object. How Should I go about Iterating over my HashMap with the Book object?
This is my HashMap: HashMap<String, String> books = new HashMap<String, String>();
if (users.containsValue(new User(userID, null, 0))
&& books.containsValue(new Book(bookID, null))) {
// get the real user and book
Book b = null;
User u = null;
// get book
for (Book book : books) {
if (book.getId().equalsIgnoreCase(bookID)) {
b = book;
break;
}
}

You probably needs something like this. I've used names instead of ID's, but I hope you get the drift...
// setting up the test
HashMap<String, String> borrowers = new HashMap<String, String>();
borrowers.put("Lord of the Rings", "owlstead");
borrowers.put("The Hobbit", "sven");
borrowers.put("Vacuum Flowers", "owlstead");
// find out what I borrowed from the library
String userID = "owlstead";
List<String> booksBorrowed = new ArrayList<>();
// iterating through the books may not be very efficient!
for (String bookName : borrowers.keySet()) {
if (borrowers.get(bookName).equals(userID)) {
booksBorrowed.add(bookName);
}
}
// print instead of a return statement
System.out.println(booksBorrowed);

There are only Strings in your Hashmap.
No Books.
As there are no Books in the HashMap, you will never be able to get a Book object out of it.
If you want to identify Book objects with String objects, a HashMap works, but you have to set it up in this way:
HashMap<String, Book> books = new HashMap<String, Book>();
Here's a full working example of how a Hashmap could be used with Book objects:
import java.util.HashMap;
public class Book
{
private String title;
private int pages;
public Book(String title, int pages)
{
this.title = title;
this.pages = pages;
}
public String toString()
{
return title + ", " + pages + "p.";
}
public static void main(String[] args)
{
//creating some Book objects
Book theGreatBook = new Book("The great Book of awesomeness", 219);
Book klingonDictionary = new Book("Klingon - English, English - Klingon", 12);
//the Map:
HashMap<String, Book> library = new HashMap<String, Book>();
//add the books to the library:
library.put("ISBN 1", theGreatBook);
library.put("ISBN 2", klingonDictionary);
//retrieve a book by its ID:
System.out.println(library.get("ISBN 2"));
}
}
Why do you use Strings to identify objects?
The Strings are not unique, so if two books have the same ID, you will run into problems.
I would add the ID of an object as a data field to the object itself.
Making the association of an ID to an object in a HashMap works, but is very lose.
Without the map, the association is gone.
It's also prone to error, as typos in your Strings cannot be cached by the compiler.
Maybe you run into a NullPointerException at runtime.
Especially because also your User class has such an "ID" I am wondering if you add this to every class and would like to say that there really is no need to do this (unless you have other reasons).
To identify an object, simply use the reference to the object.
If you have a typo in one of your variable names that reference an object, the compiler will be able to tell you so.

Related

Checking if a user defined item exists in a HashSet

Im making a class called Book which contains the books name and price. If i insert those data into a HashSet, how would be i able to check if a book exists in that HashSet by only searching for the book name?
I currently have:
public Book(String name, double price){
this.name = name;
this.price = price;
}
public static void main(String[] args){
HashSet<Book> hs = new HashSet<Book>();
Book book1 = new Book("Plant Book", 19.99);
Book book2 = new Book("Garden Book", 24.99);
Book book3 = new Book("Cook Book", 14.99);
hs.add(book1);
hs.add(book2);
hs.add(book3);
System.out.println(hs.contains("Plant Book")); //I want this to return true
}
So how would i be able to search for Plant Book in this HashSet?
Using a stream can make life quite easy sometimes:
hs.stream().anyMatch(book -> "Plant book".equals(book.getName()));
Definitely recommend implementing equals and hashCode for the class that will be added to the HashSet since that will solve the use case of not allowing "similar" items to be added to the HashSet.
For your requirements, iterating over the items and checking for the name is likely the best thing to do.
As was mentioned in the comments by Thomas, it seems a map would better suit your requirements. Here I am using a record to demonstrate.
Everything is pretty much the same except for the methods used for accessing and testing a map.
record Book(String getName, double getPrice){}
Map<String, Book> hmap = new HashMap<>();
Book book1 = new Book("Plant Book", 19.99);
Book book2 = new Book("Garden Book", 24.99);
Book book3 = new Book("Cook Book", 14.99);
// using put to enter the name and Book instance
hmap.put(book1.getName(),book1);
hmap.put(book2.getName(),book2);
hmap.put(book3.getName(),book3);
// here using containsKey for the check
String name = "Plant Book";
if (hmap.containsKey(name)) {
System.out.println(hmap.get(name));
}
prints
Book[getName=Plant Book, getPrice=19.99]
You can also put the keys in lowercase or uppercase names and then just use the required case names for checking and retrieval.
hmap.put(book.getName().toLowerCase(), book);

Updating a hashmap within a hashmap with a class

Sorry about the title really struggling to name this. Lets see how the question goes.....
In java I have a class called book which contains the following code. Where name is the book name, the hashMap string is the critics name and the hashMap Integer is the critic score.
public class book {
private String name;
private HashMap<String, Integer> results = new HashMap<String, Integer>();
}
I then have another class called bookRecord which contains the following code.
private HashMap<Integer, Book> bookRecord = new HashMap<Integer, Book>();
I have written a UI that allows me to enter a new book and save that book into the bookRecord.
The Integer in bookRecord is an ID for the book.
I have written a query to search by the ID and return the name of the book. Now I want to be able to update the book if a new critic and score is available.
I have been playing with a for each loop to find the right key in the book record and then if the key is found another for each loop but I have confused myself.
Any advice?
You have two options:
First option you make the results HashMap public and can achieve something like this:
Book uBook = records.get(BOOK_ID_YOU_WANT_TO_UPDATE);
if (uBook != null) {
uBook.results.put("New critic name", Critic_SCORE);
}
Seconds option is to leave the results private but add a new method addCriticScore(String criticName, Integer score):
// In your class that updates the book
Book uBook = records.get(BOOK_ID_YOU_WANT_TO_UPDATE);
// In the Book class
public void addCriticScore(String criticName, Integer score) {
this.results.put(criticName, score);
}
P.S: Don't forget to rename your class book to Book. In java the class name is with capitals

Adding objects to an array based on a String attribute?

I'm coding an application for a year-long school project, and its purpose is to display articles for teens to read that educate them on current events.
I want to make several different ArrayLists of categories to store the Articles in. The objects are Article(String URL, String Category, String title)
I'm wondering if, instead of doing this:
Article p = new Article(
"http://www.google.com", "economics", "Potato Article");
if(category.equals("elections"))
elections.add(p);
if(category.equals("economics"))
economics.add(p);
// etc.
If there is some thing I can do like this:
String name = category;
(something).something(name);
name.add(p);
So basically I want to add the article to an ArrayList of the same name as its category, assuming the ArrayList is made already, and the category of the particular article matches the desired ArrayList.
Data structure should be Map<String, List<Article>>, so a sample code could be as follows :
Map<String, List<Article>> map =
new HashMap<String, List<Article>>();
map.put("elections", new ArrayList<Article>());
map.put("economics", new ArrayList<Article>());
Article article1 = new Article(
"http://www.google.com", "economics", "Potato");
Article article2 = new Article(
"http://www.yyy.com", "elections", "xxx");
map.get(article1.getCategory()).add(article1);
map.get(article2.getCategory()).add(article2);

Guava: get a list of variables from a list of objects containing the variable

The idea:
I have an object
public class Book(){
private String name;
private Integer nbOfPage;
public Book()
...
}
And I got a list of this Object
List<Book> books = new ArrayList<Book>();
Now I was wondering if in guava or another librairie, there was a quick way to get a list of all the different names from all the books I got, something I could do:
List<String> names = new ArrayList<String>();
for (Book aBook : books){
if (!names.contains(aBook.getName()){
names.add(aBook.getName());
}
}
I think this way is a bit "heavy", my book list can have from 200 to 1200 books.
Regards,
Use Guava's Multimaps.index. It does exactly what you'd expect it does.
List<Book> books = ...
Function<Book,String> bookToName = new Function<Book,String>() {
String apply(Book b) { return b.getName(); }
}
Multimap<String,Book> booksByName = Multimaps.index(books, bookToName);
Then, play around with your Multimap, like booksByName.keys() if you need only the names.
Use a Set (such as HashSet) for the book names collection, this way you don't have to check every time whether you already have the current book name. You can insert elements in constant time into a HashSet, and you will have no duplicates. Make sure you have a good hashCode() method and a corresponding equals, see this: What issues should be considered when overriding equals and hashCode in Java?
A faster solution does not exist, because you have to iterate over all the books at least once.

Using ArrayList to store variables

I'm coding a project to store an array of objects, probably in an arraylist.
So, my object has data elements, getters and setters. I do not have an idea how to access the elements of the object.
For example my object is a book which has the following data elements.
Book
->Author
->Price
->Date
If the price of a certain book changes, how do I update the arrayList? Do I need a 2d arrayList? I think indexOf would not work because it is an object? Not really sure.
I'm just a newbie in programming, so I'm not sure if arrayList is the right data structure to use. Thank you very much for reading this, your help will be appreciated.
You can access an object in an ArrayList by it's index. Say you want the third book:
List<Book> lisOfBooks = someFunctionWhichGetsListOfBooks();
Book book = listOfBooks.get(2);
(Remember indexes start at 0 in java) Then you can do:
String Author = book.getAuthor();
or to set the price:
book.setPrice(newPrice);
If you do not know where in the list the particular book is you have 2 choices: 1) iterate through the list until you find the book you want or 2) you can use a HashMap. But you need to decide what to key the book on (what makes each book unique?). Let's say you'll be looking up books by id. Then you can put all your books in a HashMap keyed by an Integer id:
HashMap<Integer, Book> bookHash = new HashMap<Integer, Book>();
for (Book book : listOfBooks) {
bookHash.put(book.getId(), book);
}
Then to retrieve any book you can do:
Book book = bookHash.get(bookId);
Obviously this assumes your Book class has appropriate getter and setter methods. E.g:
public class Book {
private int id;
private String author;
...
public String getAuthor() {
return author;
}
public void setPrice(price) {
this.price = price;
}
...
}
An ArrayList is a good implementation if you need to store your objects in a list. A good alternative for a collection of books: a Map implementation. This is useful if every book can be identified by a unique key (name, ISBN number, ...) and you use that key to "get" a book from the collection.
A book is an object on its on and should be modeled with a Book class. So if you want to store books in list structure, this would be OK:
List<Book> books = new ArrayList<Book>();
books.add(new Book("Robert C. Martin","Clean Code"));
books.add(new Book("Joshua Bloch","Effective Java"));
For a map, a code fragment could look like this:
Map<String, Book> books = new HashMap<String, Book>();
books.put("978-0132350884", new Book("Robert C. Martin","Clean Code"));
books.put("978-0321356680", new Book("Joshua Bloch","Effective Java"));
Edit - finding a book and updating the price
With a list, you have to iterate through the list until you find the object that represents the book you're looking for. It's easier with the map shown above, if you always can use the ISBN, for example. With the list, it goes like this:
List<Book> books = getBooks(); // get the books from somewhere
for (Book book:books) {
if (matchesSearchCriteria(book)) { // some method to identify a book, placeholder!
book.setPrice(newPrice); // modify the books price
break;
}
}
You need to create a custom "datatype", basically a POJO (Plain old java object) that will have fields for all the parameters you want. Let's call it Book:
class Book {
public String author;
public double price;
public Date date;
}
Of course it's better to have private fields and encapsulate with getters and setters, i jsut wrote that for simplicity.
Then you can create a List of Book objects.
List<Book> books = new ArrayList<Book>();
And add Books to it which you can then later iterate through like this:
for (Book book : books) {
System.out.println(book.getAuthor());
}
I'd be looking at some sort of lookup data structure like a hashmap, for example
HashMap<String, Hashmap<String,String>> books = new Hashmap<String, HashMap<String, String>>();
HashMap<String, String> bookelements = new HashMap<String,String>();
bookelements.put("Author","J.K Rowling");
bookelements.put("Price","£5");
bookelements.put("Year","2000");
books.put("harry potter",bookelements);
//Get elements like so
String author = (String)books.get("harry potter").get("Author");

Categories