I am trying to make a markov chain in Java/Processing, that will read a book then be able to cut it up in probabilistic ways. Programming is a hobby…
I had the idea that the way to do it was to use a HashMap, and store a Word Object within it. I could easily do this with a String, but within each unique Word it needs to have another HashMap that will store more yet more Word Objects for the Words that follow it, and so on until we have made a model with a sufficient level of complexity.
The problems are that I can’t seem to be able to check whether or not a Word Object is already within the Map by its String name.
Through looking around on SO I can see that it is likely that I will need a Comparator — but all the examples that I have seen use compare or compareTo, when I think that I need something that is more like equals? I don’t need anything at all to do with Sorting, the order will be worked out in the second part of the program.
The code below is pretty horrible — I have been hacking away at this problem for ages but I can’t find an explanation that is sufficiently dumbed down enough for me to understand it.
In Pseudo:
read book
If the Word is not in the Map, put it in there
If the Word is in the Map, iterate the key
Check the Words that follow this Word, and check in the same way if they are within the first Word’s Map, adding as necessary… repeat…
When this is complete
Using the Integer values as probabilities, pick a word
from that Word’s Map, find a Word that is probable to follow it
repeat until desired length is achieved
Code so far:
///markovs
import java.util.HashSet;
import java.util.Comparator;
HashMap<Word, Integer> book;
void setup()
{
book = new HashMap<Word, Integer>();
String[] rows = loadStrings("crash.txt");
for (int i = 0; i < rows.length; i++)
{
if (trim(rows[i]).length() == 0)
{
continue;
}
String[] pieces = split(rows[i], " ");
for (int j = 0; j<pieces.length; j++)
{
Word temp = new Word(pieces[j]);
//c++;
if (book.compare(temp)) {
println("this worked for once");
//iterate here
} else {
book.put(temp, 1);
println("didn’t work");
//book.add(temp);
book.put(temp, 1);
}
}
}
println(book.size());
//println(c);
//println(book);
}
class WordComparator implements Comparator<Word> {
#Override
public int compare(Word w1, Word w2) {
String w1name = w1.name;
String w2name = w2.name;
if (w1name.equals(w2name)) {
return 1;
} else {
return 0;
}
}
}
class Word
{
String name;
int value=1;
int depth;
HashMap<String, Integer> list;
Word(String name_)
{
this.name = name_;
}
int compareTo(Word w) {
if (w.name.equals(this.name)) {
return 0;
} else {
return -1;
}
}
Word(Word w)
{
this.depth = w.depth+1;
}
void nextWord(String word)
{
}
void count() {
value++;
}
void makeHash()
{
list = new HashMap<String, Integer>();
}
}
To use an Object as a key in a HashMap, you need to override two methods: equals() and hashCode(). I'm not exactly sure what you're going for, but a simple example that just uses the name variable would look like this:
public boolean equals(Object other){
if(other instanceof Word){
return this.name.equals(((Word)other).name);
}
return false;
}
public int hashCode(){
return name.hashCode();
}
However, if you're just using the name variable anyway, you might be looking for a multimap, which is just a Map that contains a Map that contains...
HashMap<String, HashMap<String, Integer>> bookMap;
Furthermore, while HashMap does not use the compareTo function, the way you've implemented it seems off. First of all, you need to implement Comparable on your class:
class Word implements Comparable<Word>{
And secondly, the compareTo function should return one of 3 values: negative, zero, or positive. Right now you're only returning zero or negative, which doesn't make any sense.
I think you might be better off taking a step back and describing what you're actually trying to do, as your code contains a lot of confusing logic right now.
As for comparing, you can override Object's inherited equals method, something like:
# Override
boolean equals(Object o) {
return o instanceof Word
? o.name.equals(name) : false;
}
Be aware of using your own types as keys for the HashMap, in this case Word. That only works out well if you provide a sensible implementation of .hashCode() and .equals() on Word.
Here it looks like you could just use String instead. String already has the required method implementations. If you really do want to use Word, you could use those methods from String. e.g.
class Word {
String letters;
public int hashCode() {
return letters.hashCode();
}
public boolean equals(Object o) {
if (o == null || o.getClass() != getClass()) return false;
return letters.equals(((Word) o).letters);
}
}
You don't need a compare or compareTo, just these two.
Related
I have implemented a TreeMap that contains blueprints (to simplify it).
private TreeMap<BuildingFloorKey, Blueprint> blueprints = new TreeMap<>((o1, o2) -> {
int value = o1.compareTo(o2);
return value;
});
To use building (in my case called complex) and floor as a tuple key, I wrote the following class:
public static class BuildingFloorKey {
private Complex mComplex;
private int mFloor;
public BuildingFloorKey(Complex complex, int floor){
mComplex = complex;
mFloor = floor;
}
#Override
public boolean equals(Object other) {
if (!(other instanceof BuildingFloorKey)) return false;
BuildingFloorKey that = (BuildingFloorKey) other;
return mFloor == that.mFloor && mComplex.equals(that.mComplex);
}
#Override
public int hashCode() {
return Arrays.hashCode(new Object[]{mComplex, mFloor});
}
public int compareTo(BuildingFloorKey otherKey){
if(this.equals(otherKey)) return 0;
//same complex -> compare floors
else if (this.getComplex().equals(otherKey.getComplex())){
return otherKey.getFloorInt() - this.getFloorInt();
}
//different complexes (incl. some modification for special cases)
else return -(Math.abs(otherKey.mFloor + 2) + 100);
}
}
I am working on an Android App and I want to click through the blueprints via buttons. For that I make use of the methods TreeMap.lowerKey(otherKey) and TreeMap.higherKey(otherKey). Like so:
#Override
public void onNextPlanClicked() {
nextFloorPlan = blueprints.higherKey(currentlyDisplayedPlan);
drawFloorPlan(nextFloorPlan);
}
As an example, I have a usecase where the set of blueprints is
04|02
03|03
04|-1
03|00
(format: complex|floor). Unfortunately, it is not sorted properly in the TreeMap (as you can see - the list above is sorted like the entries of the TreeMap in the debugger).
I read something about TreeMap Sorting using case-sensitive Strings. But I'm actually using integers. So I don't get why sorting and using lowerKey() and higherKey() not working properly. Did I mess up with the comparator? Can someone help please?
I think your issues is a very simple one, your compareTo method should have an override. You need to add implements Comparable to your BuildingFloorKey definition, which will then take your compareTo argument as a comparable that TreeMap can recognize.
I am getting a warning that watchStore.contains(s) is a suspicious call to java.util.Collection#contains. How can I fix it? I want to use contains() to find a particular object with the matching serial number.
public Watch findWatchBySerialNumber(long srch) {
long s = srch;
Watch watch = null;
for(int i = 0; i < watchStore.size(); i++) {
watch = watchStore.get(i);
if(watchStore.contains(s)) {
System.out.print("item found");
return watch;
}
}
System.out.print("item not found");
return null; // watch is not found.
}
Presuming that Watch is the class, watchStore is a List<Watch>, and that a field serialNo exists on Watch...
public Optional<Watch> findWatchBySerialNumber(long serial) {
return watchStore.stream()
.filter(w -> w.getSerialNo() == serial)
.findFirst();
}
If you're not using Java 8, the code is close, but a bit more dangerous since you have the chance to return null. If you can use Guava's Optional, that'd be a better choice here.
public Watch findWatchBySerialNumber(long serial) {
for(Watch w : watchStore) {
if(w.getSerialNo() == serial) {
return w;
}
}
return null;
}
Your contains isn't going to work since your list doesn't contain Longs, it contains Watchs. This is also why the compiler sees it as dubious; contains accepts an Object but it will return false if what you're looking for doesn't have a comparable equals for what's in your list.
You have to iterate over the entirety of your collection to find it in this scenario, especially since you're looking for a specific property on those objects as opposed to a specific, easy-to-provide value.
please how can I fix that. I want to use the contain() to find a
particular object with the matching serial number.
In that case override Watch's equals() to use serialNumber field for comparison.
Then add constructor that accepts serialNumber.
public class Watch {
private final long serialNumber;
public Watch(long serialNumber) {
this.serialNumber = serialNumber;
}
#Override
public boolean equals(Object obj) {
return obj == this ||
(obj instanceof Watch && ((Watch)obj).serialNumber == serialNumber);
}
#Override
public int hashCode() {
return (int)serialNumber;
}
}
Replace if(watchStore.contains(s)){ with if(watchStore.contains(watchToFind)){ where Watch watchToFind = new Watch(s);
you can use contains method from org.apache.commons.lang.ArrayUtils package.
Checks if the value is in the given array.
The method returns false if a null array is passed in.
Parameters:
array the array to search through
valueToFind the value to find
Returns:
true if the array contains the object
long [] imageHashes= {12l,13l,14l,15l};
System.out.println(ArrayUtils.contains(imageHashes, 13l));
I was making a rock paper scissors game and I'm supposed to save the last four throws of the user into a HashMap. The last four throws will be inside a Pattern class. I have it so that if the pattern is already in the HashMap, then the value will be incremented by one, showing that the user have repeated that pattern one time. The patterns will be used to predict the user next move. However, when I compare the two patterns, the one in the HashMap and the one I just passed in, even though they are not the same, it returns that they are the same. I have tried looking into this for a while but I couldn't find out what's wrong. Some help would be greatly appreciated! The error comes right at the second input. If I input R, it will save it in the HashMapbut when I input anything else, it will throw a NullPointerException, which I think because the new pattern is not stored inside the hashmap but I tried to get the value of it since the program thinks that it is equal to the one already inside the HashMap. I think the problem is inside the equals() in Pattern but I'm not entirely sure.
import java.util.*;
public class RockPaperScisors{
public static void main(String[] args){
Scanner key = new Scanner(System.in);
Pattern pattern = new Pattern();
Pattern pattern1;
Computer comp = new Computer();
boolean stop = false;
int full=0;;
while ( !stop ){
System.out.println("Enter R P S. Enter Q to quit.");
char a = key.next().charAt(0);
if ( a == 'Q' ){
stop = true;
break;
}
pattern.newPattern(a);
char[] patt = pattern.getPattern();
for ( int i = 0; i < patt.length; i++ ){
System.out.print(patt[i] + " ");
}
pattern1 = new Pattern(patt);
comp.storePattern(pattern1);
System.out.println();
System.out.println("Patterns: " + comp.getSize());
full++;
}
}
}
import java.util.*;
public class Pattern{
private char[] pattern;
private int full = 0;
public Pattern(){
pattern = new char[4];
}
public Pattern(char[] patt){
pattern = patt;
}
public char[] getPattern(){
return pattern;
}
public void newPattern(char p){
if ( full <= 3 ){
pattern[full] = p;
full ++;
}
else{
for (int i = 0; i <= pattern.length-2; i++) {
pattern[i] = pattern[i+1];
}
pattern[pattern.length-1] = p;
}
}
public int HashCode(){
char[] a = pattern;
return a.hashCode();
}
public boolean equals( Object o ) {
if( o == this ) { return true; }
if(!(o instanceof Pattern)){ return false; }
Pattern s = (Pattern) o;
if (Arrays.equals(s.getPattern(), pattern))
System.out.println("Yes");
return Arrays.equals(s.getPattern(), pattern);
}
}
import java.util.*;
import java.util.Map.Entry;
public class Computer{
private HashMap<Pattern, Integer> map;
public Computer(){
map = new HashMap <Pattern, Integer>();
}
public void storePattern(Pattern p){
boolean contains = false;
for (Entry<Pattern, Integer> entry : map.entrySet())
{
Pattern patt = entry.getKey();
if ( p.equals(patt) ){
contains = true;
}
}
if ( contains ){
int time = map.get(p);
time++;
map.put(p, time);
}
else
map.put(p, 0);
}
public int getSize(){
return map.size();
}
}
Your HashCode is wrong.
It should be written in lower case.
public int hashCode()
In order to make sure that the method is overwritten, use the #Override annotation.
As noted by another answer, the first thing to do is rename and annotate your hashcode() method.
And then, you also have to fix it. It uses
char[] a = pattern;
return a.hashCode();
This means it uses the char[] object's hashCode() function. But that function is inherited directly from Object, and gives you a different hash code for two equal character arrays. For example, try this:
char[] c = { 'a','b','c' };
char[] d = { 'a','b','c' };
System.out.printf("%d %d%n", c.hashCode(), d.hashCode());
And you'll see that it prints two different numbers.
So you need to use a better hash code function. You can make your own, or use Arrays.hashCode(pattern) (there is no need for the local a variable). The important thing is that when two Patterns are equal according to the equals() method, they should have the same hash code.
What happens in your case is that you look up the HashCode by testing equality of all the entry keys (I'll get to that in a minute, it's a bad thing to do), so equals tell you you have the same key in the hash map. But the hash map itself uses the hashCode() method in get() to locate the object. And according to the hashCode() method, there is no object in the hash map that has the same key!
So they must always agree when the objects are equal.
Now, as for your method of looking up the object:
boolean contains = false;
for (Entry<Pattern, Integer> entry : map.entrySet())
{
Pattern patt = entry.getKey();
if ( p.equals(patt) ){
contains = true;
}
}
if ( contains ){
int time = map.get(p);
time++;
map.put(p, time);
} else
map.put(p, 0);
This is not how you use a Map. The whole point of a HashMap is that you can see if it contains a certain key or not in O(1). What you are doing is iterating it and comparing - and that`s O(N), very wasteful.
If you implement your hashCode() properly, you can just look it up by doing map.containsKey(p) instead of that loop. And if you are certain that you are not putting null values in the map, you can simply use get() to get your pattern:
Integer time = map.get(p);
if ( time == null ) {
map.put( p, 0 );
} else {
map.put( p, time+1);
}
(You don't need to use ++, because you are not actually using time after you put it in the map).
It's entirely possible that the issue in Pattern#HashCode.
The first issue is that it's not being used (it should be Pattern#hashCode), the second is that it's not calculating what you think it is.
You may find java.util.Arrays#hashCode very useful, changing the backing from an array to a List would also work.
As a side note, Pattern is not a great choice for the name of that class, as it clashes with java.util.regex.Pattern. This is more of a problem in this case than it might be otherwise, as it can be used with Scanner.
I was asked this in interview. using Google Guava or MultiMap is not an option.
I have a class
public class Alpha
{
String company;
int local;
String title;
}
I have many instances of this class (in order of millions). I need to process them and at the end find the unique ones and their duplicates.
e.g.
instance --> instance1, instance5, instance7 (instance1 has instance5 and instance7 as duplicates)
instance2 --> instance2 (no duplicates for instance 2)
My code works fine
declare datastructure
HashMap<Alpha,ArrayList<Alpha>> hashmap = new HashMap<Alpha,ArrayList<Alpha>>();
Add instances
for (Alpha x : arr)
{
ArrayList<Alpha> list = hashmap.get(x); ///<<<<---- doubt about this. comment#1
if (list == null)
{
list = new ArrayList<Alpha>();
hashmap.put(x, list);
}
list.add(x);
}
Print instances and their duplicates.
for (Alpha x : hashmap.keySet())
{
ArrayList<Alpha> list = hashmap.get(x); //<<< doubt about this. comment#2
System.out.println(x + "<---->");
for(Alpha y : list)
{
System.out.print(y);
}
System.out.println();
}
Question: My code works, but why? when I do hashmap.get(x); (comment#1 in code). it is possible that two different instances might have same hashcode. In that case, I will add 2 different objects to the same List.
When I retrieve, I should get a List which has 2 different instances. (comment#2) and when I iterate over the list, I should see at least one instance which is not duplicate of the key but still exists in the list. I don't. Why?. I tried returning constant value from my hashCode function, it works fine.
If you want to see my implementation of equals and hashCode,let me know.
Bonus question: Any way to optimize it?
Edit:
#Override
public boolean equals(Object obj) {
if (obj==null || obj.getClass()!=this.getClass())
return false;
if (obj==this)
return true;
Alpha guest = (Alpha)obj;
return guest.getLocal()==this.getLocal()
&& guest.getCompany() == this.getCompany()
&& guest.getTitle() == this.getTitle();
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (title==null?0:title.hashCode());
result = prime * result + local;
result = prime * result + (company==null?0:company.hashCode());
return result;
}
it is possible that two different instances might have same hashcode
Yes, but hashCode method is used to identify the index to store the element. Two or more keys could have the same hashCode but that's why they are also evaluated using equals.
From Map#containsKey javadoc:
Returns true if this map contains a mapping for the specified key. More formally, returns true if and only if this map contains a mapping for a key k such that (key==null ? k==null : key.equals(k)). (There can be at most one such mapping.)
Some enhancements to your current code:
Code oriented to interfaces. Use Map and instantiate it by HashMap. Similar to List and ArrayList.
Compare Strings and Objects in general using equals method. == compares references, equals compares the data stored in the Object depending the implementation of this method. So, change the code in Alpha#equals:
public boolean equals(Object obj) {
if (obj==null || obj.getClass()!=this.getClass())
return false;
if (obj==this)
return true;
Alpha guest = (Alpha)obj;
return guest.getLocal().equals(this.getLocal())
&& guest.getCompany().equals(this.getCompany())
&& guest.getTitle().equals(this.getTitle());
}
When navigating through all the elements of a map in pairs, use Map#entrySet instead, you can save the time used by Map#get (since it is supposed to be O(1) you won't save that much but it is better):
for (Map.Entry<Alpha, List<Alpha>> entry : hashmap.keySet()) {
List<Alpha> list = entry.getValuee();
System.out.println(entry.getKey() + "<---->");
for(Alpha y : list) {
System.out.print(y);
}
System.out.println();
}
Use equals along with hashCode to solve the collision state.
Steps:
First compare on the basis of title in hashCode()
If the title is same then look into equals() based on company name to resolve the collision state.
Sample code
class Alpha {
String company;
int local;
String title;
public Alpha(String company, int local, String title) {
this.company = company;
this.local = local;
this.title = title;
}
#Override
public int hashCode() {
return title.hashCode();
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Alpha) {
return this.company.equals(((Alpha) obj).company);
}
return false;
}
}
...
Map<Alpha, ArrayList<Alpha>> hashmap = new HashMap<Alpha, ArrayList<Alpha>>();
hashmap.put(new Alpha("a", 1, "t1"), new ArrayList<Alpha>());
hashmap.put(new Alpha("b", 2, "t1"), new ArrayList<Alpha>());
hashmap.put(new Alpha("a", 3, "t1"), new ArrayList<Alpha>());
System.out.println("Size : "+hashmap.size());
Output
Size : 2
I have created a short example of my problem. I'm creating a list of objects anonymously and adding them to an ArrayList. Once items are in the ArrayList I later come back and add more information to each object within the list. Is there a way to extract a specific object from the list if you do not know its index?
I know only the Object's 'name' but you cannot do a list.get(ObjectName) or anything. What is the recommended way to handle this? I'd rather not have to iterate through the entire list every time I want to retrieve one specific object.
public class TestCode{
public static void main (String args []) {
Cave cave = new Cave();
// Loop adds several Parties to the cave's party list
cave.parties.add(new Party("FirstParty")); // all anonymously added
cave.parties.add(new Party("SecondParty"));
cave.parties.add(new Party("ThirdParty"));
// How do I go about setting the 'index' value of SecondParty for example?
}
}
class Cave {
ArrayList<Party> parties = new ArrayList<Party>();
}
class Party extends CaveElement{
int index;
public Party(String n){
name = n;
}
// getter and setter methods
public String toString () {
return name;
}
}
class CaveElement {
String name = "";
int index = 0;
public String toString () {
return name + "" + index;
}
}
Given the use of List, there's no way to "lookup" a value without iterating through it...
For example...
Cave cave = new Cave();
// Loop adds several Parties to the cave's party list
cave.parties.add(new Party("FirstParty")); // all anonymously added
cave.parties.add(new Party("SecondParty"));
cave.parties.add(new Party("ThirdParty"));
for (Party p : cave.parties) {
if (p.name.equals("SecondParty") {
p.index = ...;
break;
}
}
Now, this will take time. If the element you are looking for is at the end of the list, you will have to iterate to the end of the list before you find a match.
It might be better to use a Map of some kind...
So, if we update Cave to look like...
class Cave {
Map<String, Party> parties = new HashMap<String, Party>(25);
}
We could do something like...
Cave cave = new Cave();
// Loop adds several Parties to the cave's party list
cave.parties.put("FirstParty", new Party("FirstParty")); // all anonymously added
cave.parties.put("SecondParty", new Party("SecondParty"));
cave.parties.put("ThirdParty", new Party("ThirdParty"));
if (cave.parties.containsKey("SecondParty")) {
cave.parties.get("SecondParty").index = ...
}
Instead...
Ultimately, this will all depend on what it is you want to achieve...
List.indexOf() will give you what you want, provided you know precisely what you're after, and provided that the equals() method for Party is well-defined.
Party searchCandidate = new Party("FirstParty");
int index = cave.parties.indexOf(searchCandidate);
This is where it gets interesting - subclasses shouldn't be examining the private properties of their parents, so we'll define equals() in the superclass.
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof CaveElement)) {
return false;
}
CaveElement that = (CaveElement) o;
if (index != that.index) {
return false;
}
if (name != null ? !name.equals(that.name) : that.name != null) {
return false;
}
return true;
}
It's also wise to override hashCode if you override equals - the general contract for hashCode mandates that, if x.equals(y), then x.hashCode() == y.hashCode().
#Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + index;
return result;
}
If you want to lookup objects based on their String name, this is a textbook case for a Map, say a HashMap. You could use a LinkedHashMap and convert it to a List or Array later (Chris has covered this nicely in the comments below).
LinkedHashMap because it lets you access the elements in the order you insert them if you want to do so. Otherwise HashMap or TreeMap will do.
You could get this to work with List as the others are suggesting, but that feels Hacky to me.. and this will be cleaner both in short and long run.
If you MUST use a list for the object, you could still store a Map of the object name to the index in the array. This is a bit uglier, but you get almost the same performance as a plain Map.
You could use list.indexOf(Object) bug in all honesty what you're describing sounds like you'd be better off using a Map.
Try this:
Map<String, Object> mapOfObjects = new HashMap<String, Object>();
mapOfObjects.put("objectName", object);
Then later when you want to retrieve the object, use
mapOfObjects.get("objectName");
Assuming you do know the object's name as you stated, this will be both cleaner and will have faster performance besides, particularly if the map contains large numbers of objects.
If you need the objects in the Map to stay in order, you can use
Map<String, Object> mapOfObjects = new LinkedHashMap<String, Object>();
instead
As per your question requirement , I would like to suggest that Map will solve your problem very efficient and without any hassle.
In Map you can give the name as key and your original object as value.
Map<String,Cave> myMap=new HashMap<String,Cave>();
I would suggest overriding the equals(Object) of your Party class. It might look something like this:
public boolean equals(Object o){
if(o == null)
return false;
if(o instanceof String)
return name.equalsIgnoreCase((String)o);
else if(o instanceof Party)
return equals(((Party)o).name);
return false;
}
After you do that, you could use the indexOf(Object) method to retrieve the index of the party specified by its name, as shown below:
int index = cave.parties.indexOf("SecondParty");
Would return the index of the Party with the name SecondParty.
Note: This only works because you are overriding the equals(Object) method.
You could simply create a method to get the object by it's name.
public Party getPartyByName(String name) {
for(Party party : parties) {
if(name.equalsIgnoreCase(party.name)) {
return party;
}
}
return null;
}