I'm using a HashMap in which I use an ArrayList as a value.
Like this:
Map<Movie, List<Grades>> gradedMovies = new HashMap();
I'm trying to create a method with which I could iterate through the values to see if a key(movie) already exists. If it does, I would like to add a new value(grade) into the list that is assigned to the particular key(movie). Something like this:
public void addGrade(Movie movie, Grade grade) {
// stuff here }
Ultimately I wan't to be able to print a Map which would display the Movies and its' grades after they've been added to the map.
How is this accomplished? Or is my whole approach (using a Map) totally wrong?
Thanks for any assistance. (This is homework)
I think you're on the right path, just make sure your movie object implements equals and hashCode so it can work as a true key for the hash map.
If you want pretty printing just implement the toString method.
public void addGrade(Movie movie, Grade grade) {
if (!gradedMovies.containsKey(movie)) {
gradedMovies.put(movie, new ArrayList());
}
gradedMovies.get(movie).add(grade);
}
hope this helps, Cheers!
You can use something like that:
public void addGrade(Movie movie, Grade grade) {
if (!gradedMovies.containsKey(movie)) {
gradedMovies.put(movie, new ArrayList<Grade>());
}
gradedMovies.get(movie).add(grade);
}
You need override the method equals
I don't know why you're looking for an index particularly - the point of a Map is that you can look up entries by their keys.
So as a starting point, the first line of your addGrade method could look like
List<grades> grades = gradedMovies.get(movie);
and you can hopefully take it from there. (Remember to look at the documentation to see what happens if the map doesn't contain the given movie yet...)
I could iterate through the values to see if a key(movie) already exists
You don't need to iterate through the map, just call gradedMovies.containsKey( movieToCheck ).
Note that when using Movie as a key you should provide a sensible implementation of equals() and hashCode().
You're doing ok! but you should consider a couple of things:
While finding a value on the map, your Movie object has to override equals and hashChode. Java will always use the equals method on comparations, mainly when it comes to automatic ones (like verifying if a list contains an item or, in this case, if a key value is equal to a given one). Remember that equals defines the uniquity of an item, so you should make a comparation based on a particulary unique attribute, like an identification number or (for this case) it's name.
To print the map, iterate over the keySet, either manually (enhanced "for" loop) or with an iterator (which can be obtained directly through the .iterator() method). For each movie, you print the list of grades in a similar fashion.
I don't know if you're familiar with String printing, but some special combination of characters can be added to a String to give it some sort of formatting. For example:
\n will insert a line break
\t is a tabulation
Hope this helps to erase some doubts. Good luck!.
Check out Guava's Multimap. That is exactly what it does.
private Multimap<Movie, Grade> map = ArrayListMultimap.create();
public void addGrade(Movie movie, Grade grade){
map.put(movie, grade);
}
It will take care of creating the list for you.
public void addGrade(Movie movie, Grade grade) {
boolean found = false;
for(Movie m : gradedMovies.keyset()) {
// compare the movies
if(/* match on movies */) {
gradedMovies.get(m).add(grade);
found = true;
}
}
if(!found) {
gradedMovies.put(movie, new ArrayList().add(grade));
}
}
gradedMovies.containsKey(movie);
for(Map.Entry<Movie,List<Grades>> entry : gradedMovies.entrySet()){
Movie key = entry.getKey();
}
Related
Please explain output of below code. I guessed it null , because command line arguments are different than its key. But it is not correct explanation. It is null because friends class doesnot override equals and hashcode() methods.
But why?
import java.util.*;
public class Birthdays {
public static void main(String[] args) {
Map<Friends, String> hm = new HashMap<Friends, String>();
hm.put(new Friends("Charis"), "Summer 2009");
hm.put(new Friends("Draumur"), "Spring 2002");
Friends f = new Friends(args[0]);
System.out.println(hm.get(f));
}
}
class Friends {
String name;
Friends(String n) { name = n; }
}
And the command line invocation:
java Birthdays Draumur
args[0] will contain the string "Draumur", so that is not the reason for the program printing null.
A HashMap is a hash table, and it finds elements in it based on the hash value of the key. If you don't override the hash method, Java will calculate the hash value based on the object identity, so two different Friends objects, even with the same name inside, will not be guaranteed to hash to the same value.
You would also need to write an equals method, since if you don't override it, Java will also consider two different Friends objects not to be equal, even with the same name inside.
In summary, you need to override the hashCode method so the HashMap can find the Friends object, and you need to override the equals method so the HashMap, when it has found it, can see that it is the object it is searching for.
Here is a possible new version of the Friends class (and I would also suggest you call it Friend, since one such object represents one single friend):
class Friends {
String name;
Friends(String n) { name = n; }
public boolean equals(Object o) {
if (!(o instanceof Friends))
return false;
Friends rhs = (Friends)o;
return (name.equals(rhs.name));
}
public int hashCode() {
return name.hashCode();
}
}
command line arguments are different than its key
Not sure I understand that logic...
args = {"Draumur"}
new Friends(args[0]) = new Friends("Dramur")
A key like that was placed in the map already, but a Friend is not comparable to other Friend objects via a hashcode or equality otherwise.
If you had a HashMap of String to String, then get("Dramur") would not be null.
The get method of a map return the value of the key where map key ".equals" to researched key
Your Friends key do not implements equals, so the default one from Object is used, which is a "==" compare (true only if it is the same object).
Get will only give you something if you use the exact same object you put as key.
I have a List<String> theList
which has following kind of values
"2011-05-05|~JKED"
"2011-05-06|~ABC"
"2011-05-01|~XYZ"
"2011-05-01|~WWX"
As you could guess there are two "fields" in theList.
I want to sort theList on first field and then on second field such as I get following output after sorting operation
"2011-05-01|~WWX"
"2011-05-01|~XYZ"
"2011-05-05|~JKED"
"2011-05-06|~ABC"
If I take these two fields in a separate lists and do Collections.sort(field1List) Collections.sort(field2List) I get the desired output.
But, I want to know, how to use Collections.sort(theList, new Comparator(){}) to be able to sort above theList to get desired output. If it is not possible to solve through Comparator(), please suggest some method which might look like sortMultiFieldList(List<String> theList)
It is a long story why I have to have two or more fields in a single List.
Let me know if you need more clarification.
This is remarkably straightforward. You'll want to write a custom Comparator for this, and enforce its comparison logic to behave the way you want with respect to your two separate "fields".
The motivation here is that these fields are lexicographically compared to one another for the date portion, as well as the alphabetical string portion. If you find that the date comparison isn't giving you accurate results (and it may not; I'm not sure of any cases that it wouldn't work off hand, though), then convert it to a Date and compare that in-line.
Collections.sort(entries, new Comparator<String>() {
#Override
public int compare(String left, String right) {
String[] leftFragments = left.split("[|]");
String[] rightFragments = right.split("[|]");
if(leftFragments[0].compareTo(rightFragments[0]) == 0) {
return leftFragments[1].compareTo(rightFragments[1]);
} else {
return leftFragments[0].compareTo(rightFragments[0]);
}
}
});
Below is my class. The insertSymbol method is supposed to add an object to the linked list which is then added to a hash table. But when I print the contents of the hash table it has double entries. I tried to correct this by using "if(temp.contains(value)){return;}" but it isn't working. I read that I need to use #override in a couple of places. Could anyone help me know how and where to use the overrides? Thank you!
import java.util.*;
public class Semantic {
String currentScope;
Stack theStack = new Stack();
HashMap<String, LinkedList> SymbolTable= new HashMap<String, LinkedList>();
public void insertSymbol(String key, SymbolTableItem value){
LinkedList<SymbolTableItem> temp = new LinkedList<SymbolTableItem>();
if(SymbolTable.get(key) == null){
temp.addLast(value);
SymbolTable.put(key, temp);
}else{
temp = SymbolTable.get(key);
if(temp.contains(value)){
return;
}else{
temp.addLast(value);
SymbolTable.put(key, temp);
}
}
}
public String printValues(){
return SymbolTable.toString();
}
public boolean isBoolean(){
return true;
}
public boolean isTypeMatching(){
return true;
}
public void stackPush(String theString){
theStack.add(theString);
}
}
You have multiple options here. You'll need at least to add an equals (and therefor also a hashcode) method to your class.
However, if you want your collection to only contain unique items, why not use a Set instead?
If you still want to use a List, you can use your current approach, it just that the characteristics of a Set are that all items in a Set are unique, so a Set might make sense here.
Adding an equals method can quite easily be done. Apache Equalsbuilder is a good approach in this.
You don't need the 2nd line when you add a new value with the same key:
temp.addLast(value);
SymbolTable.put(key, temp); // <-- Not needed. Its already in there.
Let me explain something that #ErikPragt alludes to regarding this code:
if(temp.contains(value)){
What do you suppose that means?
If you look in the javadocs for LinkedList you will find that if a value in the list is non-null, it uses the equals() method on the value object to see if the list element is the same.
What that means, in your case, is that your class SymbolTableItem needs an equals() method that will compare two of these objects to see if they are the same, whatever that means in your case.
Lets assume the instances will be considered the same if the names are the same. You will need a method like this in the 'SymbolTableItem` class:
#Overrides
public boolean equals(Object that) {
if (that == null) {
return false;
}
if (this.getName() == null) {
return that.getName() == null;
}
return this.getName().equals(that.getName());
}
It it depends on more fields, the equals will be correspondingly more complex.
NOTE: One more thing. If you add an equals method to a class, it is good programming practice to add a hashcode() method too. The rule is that if two instances are equal, they should have the same hashcode and if not equal they don't have to be different hashcodes but it would be very nice if they did.
If you use your existing code where only equals is used, you don't need a hashcode, stricly. But if you don't add a hashcode it could be a problem someday. Maybe today.
In the case where the name is all that matters, your hashcode could just return: this.getName().hashcode().
Again, if there are more things to compare to tell if they are equal, the hashcode method will be more complex.
Say I have two comparators, a primary and a secondary. How can I sort an array first by the primary comparator, then by the secondary?
Say each object has a name and a number field.
Like
Bob 1
Bob 2
Jack 1
Jack 2
Is it possible without creating a new comparator?
Yes, you can accomplish your sort without creating a new comparator.
There is a well-known trick for sorting by a primary field, secondary, tertiary, etc: First sort by the least important field (tertiary), then the next important field (secondary), and finally the most important field (primary). But the sorting algorithm needs to be stable for this to work.
If you are sorting an array, use Arrays.sort(). If you are sorting a List, use Collections.sort(). Both of these methods are guaranteed to be stable.
Suppose your primary comparator object is stored in the variable primaryComp, and your secondary is in secondaryComp. Then here is some code to accomplish what you want:
Arrays.sort(mylist, secondaryComp); // This must come first!
Arrays.sort(mylist, primaryComp);
assuming your class is
class X {
String name;
int num;
}
then sorting will be
Arrays.sort(x, new Comparator<X>() {
#Override
public int compare(X o1, X o2) {
if (o1.name.equals(o2.name)) {
return Integer.compare(o1.num, o2.num);
}
return o1.name.compareTo(o2.name);
}});
Compare the second comparator first, and then the first comparator. I believe that should do the trick. You can create a class to do so.
class FullName {
public String firstName;
public String secondName;
}
Say you create a new name, called BobBobbins, assign values and then simple compare the second name first, and then the first name. You can have a static function to do the comparing:
public static bool compareTo ( FullName name1, FullName name2 ) {
// Algorithm here
}
Should you use a static comparator, you can will have to do this : FullName.compareTo( BobBobbins, CharlieChaplin );
The method does not show any error but I am unable to use it in main method to display the list.
if (userinput.equalsIgnoreCase("push") )
{ calc.push(value);
calc.displaylist();
System.out.println(calc.getValues());
}
else if (userinput.equalsIgnoreCase("mult"))
{ calc.push(calc.mult());
calc.getValues(); }
how to use this method ... instead i used a methos called display list and that works but i need to know how to use my getValues method. both the methods are as below :
Double[] getValues()
{
Double[] array = new Double[values.size()];
return values.toArray(array);
}
void displaylist()
{
for(Double d : values)
System.out.println(d);
}
You can use a static method called toString(Object[]) in the java.util.Arrays class.
Well your displaylist() method contains a for-each loop that will iterate over the contents of a collection. The collection to iterate over is on the right side of the ':'. You've got a method that returns a collection - specifically, a Double[] - so you can call your getValues() method in place of the collection.
So, try this:
void displaylist()
{
for(Double d : getValues()) System.out.println(d);
}
I'm trying to understand the question - Let me restate it and see if I got it or not:
You have an object that has a Collection (probably a List) of values called values.
You have a method, getValues(), which returns an array containing all of the values in values.
You would like to print out all of the values in values.
You are required (homework?) to use the getValues() method when printing out values in values. (If you're not required to use getValues(), then I don't see what's wrong with the displaylist() method that you already wrote.)
You tried to just call System.out.println() on the array that you got from getValues(), but that just printed something awful like "[Ljava.lang.Double;#39172e08".
Did I get it?
Unfortunately, even with all that, I'm not sure what to suggest because I don't know what you want the printed out version to look like.
Should the values be separated by commas? If so, Ash's answer will do this for you.
Should each one be on its own line? If so, Shakedown's answer will do this for you.
Should the values just be separated by spaces? If so, then you can modify Shakedown's answer to use print(d + " ") instead of println(d).