Making an add method for an ArrayList - java

So I am supposed to make an add method for an array list which adds a new movie object to the list if it doesnt exist, or if it finds a movie object with a similar title within the list, it just increases the quantity property of that object. Here is what I've got so far.
public void add(String title, double rating, int releaseYear){
if(this.myMovies.size() < 1)
{
Movie mymovie = new Movie(title, rating, releaseYear);
this.myMovies.add(mymovie);
}
else
{
for(int i = 0; i < this.myMovies.size(); i++)
{
Movie temp = this.myMovies.get(i);
if(temp.Title.equals(title)){
this.myMovies.get(i).quantity++;
break;
}
else
{
Movie mymovie = new Movie(title, rating, releaseYear);
this.myMovies.add(mymovie);
break;
}
}
}
}
My problem is that this ends up not taking account of similar names and doesn't increase the quantity but just adds another object to the list. I have a strong feeling that the problem lies within my For loop but I just can't identify it. Can anyone see anything that I may be doing wrong? Thank you!

You're testing only for equality, not similarity here:
if(temp.Title.equals(title)){
Instead, you should write a helper method to test for similarity based on whatever criteria are appropriate. For example:
if (isSimilar(temp.Title, title)){
and the isSimilar method might look something like this (assuming you don't need any input validation):
private void isSimilar(String title1, String title2) {
return title1.equalsIgnoreCase(title2)
|| title1.toLowerCase().contains(title2.toLowerCase())
|| title2.toLowerCase().contains(title1.toLowerCase());
}
or, perhaps more appropriately, like this (if you implement it in the Movie class):
private void isSimilar(otherMovie) {
return title.equalsIgnoreCase(otherMovie.title)
|| title.toLowerCase().contains(otherMovie.title.toLowerCase())
|| otherMovie.title.toLowerCase().contains(title.toLowerCase());
}
...in which case your if statement would also change slightly.
Keep in mind that I don't know what you consider 'similar'; only that the movies are considered similar if the names are similar.
A couple more comments:
Fields and method names generally start with a lowercase letter (so the field Movie.Title should instead be Movie.title).
It's usually preferable to loop over a Collection using an Iterator instead of using the raw index--partly because the Iterator should always know how to loop over the Collection efficiently.
Learn to use your IDE's debugger (it's probably very easy). Then you can step through each line of code to see exactly where your program is doing something unexpected.

I would do something like this:
public void add(String title, double rating, int releaseYear){
for(Movie m: myMovies.size())
{
if(m.Title.equals(title)){
m.quantity++;
return;
}
}
// movie with same title not found in the list -> insert
this.myMovies.add(new Movie(title, rating, releaseYear));
}
By the way: variable names should start with a lowercase character (Title -> title).

I'm addressing your "similarity" requirement. If you really want to do this properly it could be a lot of work. Essentially you have two strings and want to get a measure of the similarity. I am doing the same thing for figure captions and I plan to tackle it by:
splitting the title into words
lowercasing them
using them as features for classifier4J (http://classifier4j.sourceforge.net/)
That will go a long way based on simple word counts. But then you have the problem of stemming
(words that differ by endings - "Alien" and "Aliens"). If you go down this road you'll need to read up about Classification and Natural Language Processing

Related

Issue with implementing custom Comparator for Priority Queue in Java

Please pardon my understanding towards priority Queue and Comparator in Java.
It seems ,I am able to implement basic comparator for Priority Queue based on some sort order.
But I am not able to come up with something for the below scenario :
1. Given a list of Files with name convention xx_yy_zz.dat .<br/>
2.xx,yy,zz can be from 00-50 <br/>
3.I need to process the files with xx=30 first,xx=35 second xx=40 third and then the rest.<br/>
Since I have limited knowledge with Priority Queue ,I tried to implement it which i was able to sort but only in asc or desc value of xx which was not the requirement.
My approach was
put the list of file names in priority Queue ,split the filename on regex "_"
then compare the first index of split array using comparator based on it values but as expected i failed miserably since my requirement was something different
Please share some ideas/approach.
It seems sadly ,I am not able to come up with the a required comparator for my case .
Nevertheless thanking you in anticipation
You can use simple if statements inside the compare() method to check if one string starts with "30" and the other does not. Then you know that this string must come before the other one. You run the following if statements like this on the first part of the filenames:
Are they the same?
Is the left one 30?
Is the right one 30?
Is the left one 35?
Is the right one 35?
Is the left one 40?
Is the right one 40?
The comparator might look like this:
public int compare(String a, String b) {
String[] splitA = a.split("_");
String[] splitB = b.split("_");
if (splitA[0].equals(splitB[0])) {
return 0;
}
if (splitA[0].equals("30")) {
return -1;
}
if (splitB[0].equals("30")) {
return 1;
}
if (splitA[0].equals("35")) {
return -1;
}
if (splitB[0].equals("35")) {
return 1;
}
if (splitA[0].equals("40")) {
return -1;
}
if (splitB[0].equals("40")) {
return 1;
}
return 0;
}
With the following test source code:
System.out.println(Arrays.toString(data));
Arrays.sort(data, new SpecialComparator());
System.out.println(Arrays.toString(data));
You might get an output like this (depending on the data array):
[30_45_35.dat, 00_12_34.dat, 35_50_20.dat, 40_03_05.dat, 33_28_14.dat,
30_16_31.dat, 20_29_23.dat, 24_41_29.dat, 30_49_18.dat, 40_12_13.dat]
[30_45_35.dat, 30_16_31.dat, 30_49_18.dat, 35_50_20.dat, 40_03_05.dat,
40_12_13.dat, 00_12_34.dat, 33_28_14.dat, 20_29_23.dat, 24_41_29.dat]
(new lines added for clarity)
As you see you have the 30s first, then the only 35 second, then the 40s third and after that all the remaining stuff. You might want to use compareTo() on the strings in case the compareTo method would return 0 to get better "sub sorting" of strings, which would be equal based on this basic sorting above.
May be I'm not understand what exactly you need... but simply try this code and it sort me all strings if they has two digits on the begining
public static void main(String[] args) {
PriorityQueue<String> q = new PriorityQueue<String>((first, second) -> {
return Integer.parseInt(first.substring(0, 2)) - Integer.parseInt(second.substring(0, 2));
//and if you want to reverse order, simply add "-" like this:
//return -(Integer.parseInt(first.substring(0, 2)) - Integer.parseInt(second.substring(0, 2)));
});
q.add("23lk");
q.add("22lkjl");
q.add("45ljl");
for(String str : q) {
System.out.println(str);
}
}
}
adn output
22lkjl
23lk
45ljl
If this not solution, please explain problem with more details, may be I or anybody else will help you.

Returning an arraylist and iterating throught the returned list

Im trying to return an arraylist from the method getNumbers (which contains strings)
public ArrayList<String> getNumbers(){
return (numeros);
}
Then by using a searcher im trying to compare between a variable m (which contains the desired info to look for) and the returned list.
public class NumberSearcher {
Reader reader = new KeyboardReader();
public NumberSearcher(ArrayList<Contacto> contactos){
String m = reader.read();
for(int i = 0; i<contactos.size();i++){
if(contactos.get(i).getPhoneNumbers().contains(m)){
contactos.get(i).display();
}
}
}
}
I have succeded in creating a searcher using this very same style but only when using methods that return String alone.
The problem is its not working. If there there would be a match it should display the contact information but it seem it isnt "comparing" properly because nothing happens.
It's difficult to understand what you're asking here. Your getNumbers method doesn't get called from the second code block, so I don't see where that is relating to anything. It's also unclear what you mean the problem is. Can you try to give us a more detailed description of what is going wrong?
Anyways, I'll try to give you some general advice here, but without knowing the issue it's hard to say how much this will help.
Firstly, it is almost always recommended to have your method's return type as the List interface, rather than a specific implementation (ArrayList, etc). You can specify a return type from within the method but this way they client doesn't need to know what the underlying data structure is, and you are also flexible to future data structure changes.
public List<String> getNumbers(){
return (numeros);
}
Secondly, I would probably change the name 'getNumbers' to something slightly more precise - if I see a 'getNumbers' method I expect it to return some numeric entities, not a list of strings. If they are phone numbers then explicity call it 'getPhoneNumbers'.
Though I'm not entirely sure I understand what you asking, I think this may solve your issues:
for(int i = 0; i < contactos.size(); i++) {
Contacto next = contactos.get(i);
if(next.getEmails().contains(m)) {
next.display();
}
}
And as an afterthought, is there any specific reason you're only checking string containment? I would suggest that you check case-insensitive equality unless you really do want to find out if the string just contains the element.
Is this what you are looking for?
public class EmailSearcher {
Reader reader = new KeyboardReader();
public EmailSearcher(ArrayList<Contacto> contactos){
while(reader.read() != 'keyThatTerminates') {
String m = reader.read();
for(int i = 0; i<contactos.size();i++){
var row = contactos.get(i);
if(row.getEmails().contains(m)){
row.display();
}
}
}
}
}

Multiple and single choice test

I am working on a Single choice and Multiple choice test.
I have couple of questions and 4 answers for each question.
I am shuffling the answers as each answer is assigned to radio button.
This is how i am shuffling the arraylist where Random is a arraylist with items and r1,r2,r3,r4 are radio buttons.
random.add(val);
Collections.shuffle(random);
r1.setText(random.get(0));
r2.setText(random.get(1));
r3.setText(random.get(2));
r4.setText(random.get(3));
I am able to display the answers in jumbled way but when i select the answer i need to show that the answer is correct or wrong.
Sample question and options.
1. which language is used for android programming?
A.PHP
B.JAVA
C.C
D.C++
Correct answer is B i need to display that correct answer is B.
How to acheive this.
EDIT:
I have tried this:
Onclick of each radio button assign the value A and compare the value with xml value if its correct display correct but when i jumble its will not work.
EDIT 2
xml
<Question no="1" text="Which Programming language is used in android develoment" type="SCA" noc="4" jumble="NO" correctans="PHP">
<choice a = "PHP" flag="A">
<choice b = "JAVA" flag="B">
<choice c = "C" flag="C">
<choice d = "C++" flag="D">
You can create a hashmap with Option-isOptionCorrect pair. Like for your case:
HashMap<String, Boolean> choices = new HashMap<String, Boolean>();
choices.put("PHP", false);
choices.put("JAVA", true);
choices.put("C", false);
choices.put("C++", false);
Now shuffle the key-value pairs. Your correct choice will be one which has value true in the HashMap.
Egor is clear for what he is suggesting but I'll let you work with your current implementations.
class Option{
//You can add any other parameters if required.
String optionText;
boolean isAnswer;
}
// Use arraylist of Option class like this
ArrayList<Option> options = new ArrayList<Option>(); // in your case random
// Now suffle it.
Collections.shuffle(options);
// get the user selected option and verify using.
if(options.get(userSelectedOptionPosition).isAnswer){
//show "You are Correct!"
}else{
// show "You are In correct!"
}
Hope this will help you.
Here is a somewhat naive solution but it should work.
class Question {
String message;
String answer;
List<String> options; //"Java", "PHP", etc
}
Shuffle the keys of the Map in your Question object
In your radio buttons, do something like r1.setText(random.get(0))
On click, do
String choice = null;
for (RadioButton rb : rBtns) {
if (rb.isSelected) {
choice = rb.getText(); break();
}
}
if (choice.equals(question.getAnswer))
return true; //correct
else
return false; //wrong
The best approach here is not to operate with Strings, but to create a Question class, which will contain all the info about a question: its value, list of answers and the index of the right answer. When parsing the XML, create a list of Question objects and then work with them. There won't be any mapping problems anymore. Hope this helps.
You can hold your answers in your 'random' arraylist in a model, instead of pure strings;
private class AnswerModel {
string answer;
boolean flag;
//... getters and setters...
}
Here you can set your true answer' s flag to true, and all others to false. That way, you can simply return if the answer was correct.
There are already several good answers here. But another option is to write your own shuffle function. The shuffle algorithm is a very simple algorithm that runs in linear time, at least for arrays. By writing your own shuffle function, you can keep track of where the correct answer ends up.
To make this simple, I'm posting code that returns the new index of a specified index in a shuffled collection. The function mutates (alters) the original collection, so this should work.
/**
* #return Returns the new index of the element that was placed at correctIndex,
* or -1 if the correctIndex parameter was out of bounds.
*/
public int shuffleAnswers(Collection<String> collection, index correctIndex) {
String[] shuffleArray = new String[collection.size()];
int returnValue = -1;
collection.toArray(shuffleArray); // Convert to array
collection.clear(); // We have to add the elements again later
// Pick random elements
for (int i = shuffleArray.length; i > 0; i--) {
int randIndex = Math.random() * i;
if (returnValue == -1 && randIndex == correctIndex) {
// This only works if elements are added to the end
// So you may want to limit the function to ArrayLists or LinkedLists
returnValue = collection.size();
}
// Add the randomly selected element to the collection
collection.add(shuffleArray[randIndex]);
// We must ensure that we don't lose elements
// So we swap them down from the end
shuffleArray[randIndex] = shuffleArray[i - 1];
}
return returnValue;
}
Note like the comments say, this only works with collections that add elements to the end of the collection, and that fills arrays from the first to last element added to the collection.
This is perhaps slower than the other solutions, but note that you require a shuffle anyway, so it shouldn't affect running speed much.
Another option is just to have a correctAnswer String and then compare the user's choice to the string (with .equals()).
This is what would I do.
Since you are remembering answer in your XML file and not answers position, then on selected radio button take text (in this case it would be "PHP", "Java", "C++" or "C") and compare it with correct answer.
Jumbling can't affect on this, otherwise you are doing something wrong.

how do i use a hashmap keys to an array of strings?

im currently working on a multiple class assignment where i have to add a course based on whether the prerequisites exist within the program.
im storing my courses within the program class using a hashmap. (thought i would come in handy) however, im having a bit of trouble ensuring that these preReqs exist.
here is some code ive currently got going
public boolean checkForCourseFeasiblity(AbstractCourse c) throws ProgramException
{
AbstractCourse[] tempArray = new AbstractCourse[0];
tempArray= courses.keySet().toArray(tempArray);
String[] preReqsArray = new String[1];
preReqsArray = c.getPreReqs();
//gets all course values and stores them in tempArray
for(int i = 0; i < preReqsArray.length; i++)
{
if(courses.containsKey(preReqsArray[i]))
{
continue;
}
else if (!courses.containsKey(preReqsArray[i]))
{
throw new ProgramException("preReqs do not exist"); //?
}
}
return true;
}
ok so basically, tempArray is storing all the keySets inside the courses hashmap and i need to compare all of them with the preReqs (which is an array of Strings). if the preReqs exist within the keyset then add the course, if they dont do not add the course. return true if the course adds otherwise through me an exception. keep in mind my keysets are Strings e.g. a keyset value could be "Programming1" and the required prerquisite for a course could be "programming1". if this is the case add then add the course as the prereq course exists in the keyset.
i believe my error to be when i initialize mypreReqsArray with c.getPreReqs (note: getPreReqs is a getter with a return type String[]).
it would be really great if someone could aid me with my dilemma. ive tried to provide as much as possible, i feel like ive been going around in circles for the past 3 hours :(
-Thank you.
Try something like this, you don't need tempArray. The "for each" loop looks lots nicer too. If you want to throw an Exception I would put that logic in the place that calls this method.
public boolean checkForCourseFeasiblity(AbstractCourse c)
{
for(String each : c.getPreReqs())
{
if(! courses.containsKey(each))
{
return false;
}
}
return true;
}

Java: For loop and If algorithm

I've this question from an assignment to create a Store which rent out books, using a Store.java and Book.java. I've finished this assignment, but I'm curious for better algorithm to a specific part.
--
Book.java
public class Book {
private String name;
Book(String name)
this.name = name;
public String getName()
return name;
}
Store.java
Inside main();
Book bookObj[] = new Book[3]; //Create 3 Array of Object.
bookObj[0] = new Book("Game Over");
bookObj[1] = new Book("Shrek");
bookObj[2] = new Book("Ghost");
Scanner console = new Scanner(System.in)
input = console.nextLine();
Assuming, input = Devil.
Now, I need to do a simple search to check whether the specific book exist.
Example:
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
}
Apparently, this is a for loop that cycles through the array of object and checks whether such Book exist. Now, the problem arise when I want to give an output that the Book was not found.
Example:
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
else
System.out.println("Book not Found!");
}
The problem with the above code is that Book not Found would be printed thrice. My goal is to avoid such problem. I do have solutions to this, but I'm still in search for a better one to use that utilizes getName(), which in my opinion still has room to improve.
Usually, in structural programming, I would do the following,
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
else if(i == bookObj.length - 1)
System.out.println("Book not Found!");
}
This is useful to tell whether it's the end of the loop, and the search has ended, but there was no successful result from the search.
How should I think of it in Object Oriented way?
All in all, my question is,
Is there a better way to write the above code rather than checking that it's the end of the line?
Is there a better way to utilize getName() method or to use other methods?
You should loop through the array and use an index / boolean flag to store whether or not the book is found. Then print the message in the end, based on the index / flag value.
int foundAtIndex = -1;
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input)) {
foundAtIndex = i; // store the actual index for later use
break; // no need to search further
}
}
if(foundAtIndex >= 0)
System.out.println("Book Found!");
else
System.out.println("Book not Found!");
Alternatively (unless your assignment specifically requires using an array) you should prefer a Set, which can do the search for you with a single call to contains().
How should I think of it in Object Oriented way?
When looking at a single method, there is not much difference between procedural and OO style. The differences start to appear at a higher level, when trying to organize a bunch of conceptually related data and methods that operate on these.
The OO paradigm is to tie the methods to the data they operate on, and encapsulate both into coherent objects and classes. These classes are preferably representations of important domain concepts. So for your book store, you may want to put all book related code into your Book class. However, the above search method (and the collection of books it operates on) is not related to any particular book instance, so you have different choices:
put both the collection of books and the search method into Store (probably as regular members), or
put them into Book as static members.
The first choice is more natural, so I normally would prefer that. However, under specific circumstances the second option might be preferable. In (OO) design, there are hardly ever clean "yes/no" answers - rather tradeoffs between different options, each having their own strengths and weaknesses.
You could introduce state and remember whether you have found the book or not.
If you're not using Java 1.4 or earlier, you could also use the foreach loop syntax:
boolean bookFound = false;
for(Book currentBook : bookObj) {
if(currentBook.getName().equals(input))
//TODO: see above
}
Also, I would suggest looking into the Collections library, and replace your array with a list or set:
Set<Book> books = new HashSet<Book>();
books.put(new Book("Game Over"));
books.put(new Book("Shrek"));
books.put(new Book("Ghost"));
And, while were at it, you could also think about when two books are equal and override equals() and hashCode() accordingly. If equal() would be changed to check the title, you could simply use books.contains(new Book(input)); and have the libraries do the work for you.
To solve the problem in a better way you must understand that the power of Java comes not from the language itself but from the Java Framework.
You should learn the usage of the Java Collection classes (never work with arrays anymore). Then you will be able to solve the search with just one line of code:
ArrayList<Book> listOfBooks;
// init your list here
listOfBooks.contains(new Book(input));
To make this work, you must also learn how to correctly implement the equals() method of your Book class.
Happy learning!
Here is a working solution :
import java.util.Scanner;
public class Store {
private static class Book {
private String name;
Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static void main(String[] args) {
String input;
Book[] bookObj = new Book[3];
bookObj[0] = new Book("Game Over");
bookObj[1] = new Book("Shrek");
bookObj[2] = new Book("Ghost");
Scanner console = new Scanner(System.in);
input = console.nextLine();
boolean found = false;
int i = 0;
while(!found && i < bookObj.length) {
if(bookObj[i].getName().equals(input)) {
System.out.println("Book Found at position : " + i);
found = true;
} else {
i++;
}
}
if(!found) {
System.out.println("Book not Found!");
}
// Here i contains the indice of the element found in the array.
}
}
You've gotten some pretty good advice thus far. You asked if there was a more Object Oriented way of thinking about the problem so I thought I'd try and shed some light on it. As Peter already mentioned at this level of the design it's a single method implementation so the approach is going to be fairly similar as say a procedural approach. What's the advantage? In a word reuse. If you needed to find a book by name in lots of places then moving the code to it's own class will help.
So what you have is a single Book instance to encapsulate behavior around a single book, but you want to have behavior about multiple books, or a collection of books. You can keep the data (array of books), and the method that account on them separate as you outlined in your program. However, if we wanted to collect a place for doing behavior on a collection of books we can define a new class. Let's call it Library, and we might do something like the following:
public class Library {
private Book[] books;
private bookCount = 0;
public Library( int numberOfTotalBooks ) {
books = new Book[numberOfTotalBooks];
}
public boolean addBook( Book book ) {
if( bookCount < book.length ) {
books[bookCount++] = book;
return true;
}
return false;
}
public Book findByTitle( String title ) {
for( int i = 0; i < bookCount; i++ ) {
if( books[i].getTitle().equals( title ) ) {
return books[i];
}
}
// didn't find one
return null;
}
}
So a couple of things to note about doing things this way. One is that when we work with a Library we don't know there is an Array back there. We could use an array, a Set, a List, or a database (most common). The point being the code that calls these functions just works with the interface of Library (not a literal Java interface, but the method signature of Library). Also this is a higher level interface. We don't worry about iterating over the books, doing for loops, if statements, etc. We just call a method saying "Hey find this book title in the Library". How that's done we don't care. This is the basic tenant of Object Orientation called encapsulation, and it's deceptively powerful. It's really about how we delegate responsibility in our program, and give the details of a job to individual class or classes. If Library had only public members (i.e. books and bookCount), or getter/setters then the client wouldn't be getting any advantages because the client would still have to do all the heavy lifting. The trick to OO is figuring out what can be delegated out of an object, without creating problems. This takes practice, and experience.
The second thing here is we've separated the presentation from the act of finding a book. The method you wrote assumed the next step which was to print "Hey we found it." However, Library object simply returns the Book to you when it finds it, or null if it didn't. That makes it possible to print to the console, display in a GUI, or serialize it to a JSON stream in a server. The act of finding a book is separate from the visualization. This is another important aspect of programming in general, but some what related to object orientation and encapsulation. This is typically called separation of concerns. The console application has concerns about supporting the UI, and printing the console. While the Library just manages cataloging and managing the book collection. How those details are performed neither cares.
In the end Library is a reusable class. We can use it in a console application, desktop, web, or middleware server. More importantly is we can also reuse the calls to findByTitle or addBooks from multiple locations within a single program. Also by putting the methods with the data we create a barrier to where that function can be used. You can't do it anywhere in your program. You have to have a reference to Library. If you don't have reference to a Library instance then you shouldn't be calling it. This can be troublesome to new developers because they lack the experience to properly organize their programs to not get into trouble with this (then they start doing value objects, creating statics, singletons, etc and things turn into a big ball of mud). It's a double edged sword.
One more thing I'd like to point out is say we wanted to model two Libraries. We have a Library uptown and downtown, and we want to allow people to check out books from either Library. With OO that's really easy to represent:
Library uptown = new Library( 50 );
Library downtown = new Library( 100 );
Now we can check out books from one or the other. And I didn't use statics (i.e. global variables) so reusing that logic is really easy. These are the basics of OO so they are really deep topics. Strange how I can write so much on very simple topics. Anyway I hope this helped you understand your program a little deeper, and see how you can use OO to help you.
chubbsondubs came closest to giving a correct answer to this question
What he missed is that his algorithm is incorrect because it contains two tests, when only one is needed. The correct code requires only 3 statements and is as follows:
public boolean zLibaryContains( String title ) {
books[bookCount] = title;
int xBook = 0;
while( true )
if( books[xBook].getTitle().equals( title ) )
return xBook != bookCount;
else xBook++;
}
Noticeably smaller and faster than all other solutions. Simplify, simplify, simplify.
Object-oriented code is a crutch to support poor designs that would otherwise be too complex to understand. The goal is write code that is so easy to understand and maintain that OO is unnecessary and would make the program worse. When your program can be improved by adding OO, it means you are doing something wrong to begin with.

Categories