compareTo and Strings using a Scanner - java

I am implementing a form of leftist min heap, which stores arbitrary words by length. So, I have written a wrapper class for Scanner, and changed the compareTo, like so
public class ScannerWrapper implements Comparable<String>
//a Scanner, sc and a String, current
public int compareTo(String str){
if(current.length() > str.length()) return -1;
if(current.length() > str.length()) return 1;
else return 0;
}
where current = sc.next() and is not the \n character.
in this case, if I have ScannerWrapper.next() > foo , where foo is an arbitrary string of length > ScannerWrapper.next();
will it use the compareTo(String) that I have written, returning false, or will it do some other random thing?

After reading your question several times I think I understand what you're asking now. If you're trying to compare two instances of class ScannerWrapper with the comparison operators, then no, it's not going to work.
You can't overload operators in Java (you can in C++), therefore in order to compare instances of ScannerWrapper with each other you're going to have to call the compareTo() method.
Also, both of your if statement conditions are the same, so you might want to fix that up.

It's difficult to understand your question - so you might consider rephrasing it. Here's a shot in the dark :
public class ScannerWrapper implements Comparable<ScannerWrapper>
//your wrapper has a handle to the scanned data. Presumably it's
//initialized on construction, which is omitted here
private final String scannedData;
public String getScannedData() {
return this.scannedData;
}
public int compareTo(ScannerWrapper other) {
//if this scannedData is longer than the other, return 1
if(this.str.length() > other.getStr().length()) {
return 1;
} else if(this.scannedData.length() < other.getScannedData().length()) {
//if the other scannedData is longer return -1
return -1;
}
//if they are equal return 0
return 0;
}
}

Related

Can you have collections without storing the values in Java?

I have a question about java collections such as Set or List. More generally objects that you can use in a for-each loop. Is there any requirement that the elements of them actually has to be stored somewhere in a data structure or can they be described only from some sort of requirement and calculated on the fly when you need them? It feels like this should be possible to be done, but I don't see any of the java standard collection classes doing anything like this. Am I breaking any sort of contract here?
The thing I'm thinking about using these for is mainly mathematics. Say for example I want to have a set representing all prime numbers under 1 000 000. It might not be a good idea to save these in memory but to instead have a method check if a particular number is in the collection or not.
I'm also not at all an expert at java streams, but I feel like these should be usable in java 8 streams since the objects have very minimal state (the objects in the collection doesn't even exist until you try to iterate over them or check if a particular object exists in the collection).
Is it possible to have Collections or Iterators with virtually infinitely many elements, for example "all numbers on form 6*k+1", "All primes above 10" or "All Vectors spanned by this basis"? One other thing I'm thinking about is combining two sets like the union of all primes below 1 000 000 and all integers on form 2^n-1 and list the mersenne primes below 1 000 000. I feel like it would be easier to reason about certain mathematical objects if it was done this way and the elements weren't created explicitly until they are actually needed. Maybe I'm wrong.
Here's two mockup classes I wrote to try to illustrate what I want to do. They don't act exactly as I would expect (see output) which make me think I am breaking some kind of contract here with the iterable interface or implementing it wrong. Feel free to point out what I'm doing wrong here if you see it or if this kind of code is even allowed under the collections framework.
import java.util.AbstractSet;
import java.util.Iterator;
public class PrimesBelow extends AbstractSet<Integer>{
int max;
int size;
public PrimesBelow(int max) {
this.max = max;
}
#Override
public Iterator<Integer> iterator() {
return new SetIterator<Integer>(this);
}
#Override
public int size() {
if(this.size == -1){
System.out.println("Calculating size");
size = calculateSize();
}else{
System.out.println("Accessing calculated size");
}
return size;
}
private int calculateSize() {
int c = 0;
for(Integer p: this)
c++;
return c;
}
public static void main(String[] args){
PrimesBelow primesBelow10 = new PrimesBelow(10);
for(int i: primesBelow10)
System.out.println(i);
System.out.println(primesBelow10);
}
}
.
import java.util.Iterator;
import java.util.NoSuchElementException;
public class SetIterator<T> implements Iterator<Integer> {
int max;
int current;
public SetIterator(PrimesBelow pb) {
this.max= pb.max;
current = 1;
}
#Override
public boolean hasNext() {
if(current < max) return true;
else return false;
}
#Override
public Integer next() {
while(hasNext()){
current++;
if(isPrime(current)){
System.out.println("returning "+current);
return current;
}
}
throw new NoSuchElementException();
}
private boolean isPrime(int a) {
if(a<2) return false;
for(int i = 2; i < a; i++) if((a%i)==0) return false;
return true;
}
}
Main function gives the output
returning 2
2
returning 3
3
returning 5
5
returning 7
7
Exception in thread "main" java.util.NoSuchElementException
at SetIterator.next(SetIterator.java:27)
at SetIterator.next(SetIterator.java:1)
at PrimesBelow.main(PrimesBelow.java:38)
edit: spotted an error in the next() method. Corrected it and changed the output to the new one.
Well, as you see with your (now fixed) example, you can easily do it with Iterables/Iterators. Instead of having a backing collection, the example would've been nicer with just an Iterable that takes the max number you wish to calculate primes to. You just need to make sure that you handle the hasNext() method properly so you don't have to throw an exception unnecessarily from next().
Java 8 streams can be used easier to perform these kinds of things nowadays, but there's no reason you can't have a "virtual collection" that's just an Iterable. If you start implementing Collection it becomes harder, but even then it wouldn't be completely impossible, depending on the use cases: e.g. you could implement contains() that checks for primes, but you'd have to calculate it and it would be slow for large numbers.
A (somewhat convoluted) example of a semi-infinite set of odd numbers that is immutable and stores no values.
public class OddSet implements Set<Integer> {
public boolean contains(Integer o) {
return o % 2 == 1;
}
public int size() {
return Integer.MAX_VALUE;
}
public boolean add(Integer i) {
throw new OperationNotSupportedException();
}
public boolean equals(Object o) {
return o instanceof OddSet;
}
// etc. etc.
}
As DwB stated, this is not possible to do with Java's Collections API, as every element must be stored in memory. However, there is an alternative: this is precisely why Java's Stream API was implemented!
Streams allow you to iterate across an infinite amount of objects that are not stored in memory unless you explicitly collect them into a Collection.
From the documentation of IntStream#iterate:
Returns an infinite sequential ordered IntStream produced by iterative application of a function f to an initial element seed, producing a Stream consisting of seed, f(seed), f(f(seed)), etc.
The first element (position 0) in the IntStream will be the provided seed. For n > 0, the element at position n, will be the result of applying the function f to the element at position n - 1.
Here are some examples that you proposed in your question:
public class Test {
public static void main(String[] args) {
IntStream.iterate(1, k -> 6 * k + 1);
IntStream.iterate(10, i -> i + 1).filter(Test::isPrime);
IntStream.iterate(1, n -> 2 * n - 1).filter(i -> i < 1_000_000);
}
private boolean isPrime(int a) {
if (a < 2) {
return false;
}
for(int i = 2; i < a; i++) {
if ((a % i) == 0) {
return false;
}
return true;
}
}
}

Comparators and HashMaps for Markov Chain

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.

Initializing a class retrieved by a function Java for android

My first question on stackoverflow:
Ok so I am writing a java game for android and I am having trouble with initializing certain classes retrieved from a function/method. Here is my code:
static int unUsedCharacters = 10;
static Character char1;
static Character char2;
static Character char3;
static Character char4;
static Character char5;
static Character char6;
static Character char7;
static Character char8;
static Character char9;
static Character char10;
Character getFreeCharacter() {
if (char1 == new Character()) {
return char1;
} else if (char2 == new Character()) {
return char2;
// and so on... until 10
} else {
return char10;
}
}
public void createCharacter(String x) {
if (unUsedCharacters > 0) {
unUsedCharacters -= 1;
getFreeCharacter() = new Warrior();
//the warrior class extends the character class
} else {
/* no more characters */
}
}
So The problem is where I try to do:
getFreeCharacter() = new Warrior();
It says:
Variable expected.
Any suggestions?
(It is probarly super easy, but this is all new to me)
Thank you for reading/responding
An expression of this form...
(char1 == new Character())
... will always evaluate to false (or throw an exception). The new operator never produces a null result, and it never produces a reference to an object that existed before, but those alternatives cover all the possible values of char1 at any time. More likely you want something like this:
if (char1 == null) {
char1 = new Character();
return char1;
}
In truth, though, I would never hold the ten characters in ten independent variables. I'd probably use a List of Characters, or at worst an array.
Having gotten past that, you have a different problem. The Character you return is already an object assigned to the intended slot. You can set its properties (to the extent that its class allows you to do so), but you cannot replace it with a different object by assigning to it. Indeed, you cannot assign directly to the method result at all, but even if you stored it in a variable, assigning a different object to that variable would not have the effect you want.
(Note, by the way, that I am distinguishing between assigning to members of the method return value, which you can do, and assigning to the value itself, which you cannot do.)
I think you would be best off getting rid of getFreeCharacter() altogether. If you structure your class better then you won't need it. Instead of declaring char1 ... char10 like so:
// Yuck, don't do this
Character char1;
Character char2;
// ...
Character char1;
... do as I suggested earlier and use a List:
import java.util.ArrayList;
import java.util.List;
public MyGame {
List<Character> characters = new ArrayList<>();
// ...
}
Then, your createCharacter() method can have this form:
public void createCharacter(String x) {
if (characters.size() < 10) {
characters.add(new Warrior());
} else {
/* no more characters */
}
}
Elsewhere, you can retrieve elements of the character list via its get() method, e.g. characters.get(0). The List instance takes care of a whole lot of details that you will otherwise have to write your own code for.

compareTo() method in java (Student ids)

Learning java and having trouble with the compareTo method. I tried google but it was not much help for what i need.What i need is
// compareTo public int compareTo(Student other)
// is defined in the Comparable Interface
// and should compare the student ID's (they are positive integers).
// Must be able to handle null "other" students. A null student should be
// ordered before any student s so the s.compareTo(null) should be positive.
so basically a compareTo(), in the end this method is going to help me put my students in order based on there student ids lowest to greatest.. I'm at a brick wall and just need some help in the right direction
public int compareTo(StudentIF other) {
// do stuff
return 0;
}
There's a good tutorial about implementing compareTo() here. That said, when learning how to do something in general it's often helpful for me to see how to implement it in my specific use case - so, in this case, I would imagine something like this would suffice:
public int compareTo(StudentIF other) {
if (other == null) {return 1;} //satisfies your null student requirement
return this.studentId > other.studentId ? 1 :
this.studentId < other.studentId ? -1 : 0;
}
compareTo() is expected to return a positive value if the other object is comparitively smaller, a negative value if it's comparitively larger, and 0 if they are equal. Assuming you're familiar with the ternary operator, you'll see that that's what this is doing. If you're not, then the if/else equivalent would be:
public int compareTo(StudentIF other) {
if (other == null) { return 1; } //satisfies your null student requirement
if (this.studentId > other.studentId) return 1;
else if (this.studentId < other.studentId) return -1;
else return 0; //if it's neither smaller nor larger, it must be equal
}
As the compareTo interface required:
a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
plus your additional requirement of null comparison, we can simply check whether the other param is null or not, and then do a subtraction to compare.
public int compareTo(StudentIF other) {
if (other == null) {
return 1;
}
return this.id - other.id;
}

Treeset.contains() problem

So I've been struggling with a problem for a while now, figured I might as well ask for help here.
I'm adding Ticket objects to a TreeSet, Ticket implements Comparable and has overridden equals(), hashCode() and CompareTo() methods. I need to check if an object is already in the TreeSet using contains(). Now after adding 2 elements to the set it all checks out fine, yet after adding a third it gets messed up.
running this little piece of code after adding a third element to the TreeSet, Ticket temp2 is the object I'm checking for(verkoopLijst).
Ticket temp2 = new Ticket(boeking, TicketType.STANDAARD, 1,1);
System.out.println(verkoop.getVerkoopLijst().first().hashCode());
System.out.println(temp2.hashCode());
System.out.println(verkoop.getVerkoopLijst().first().equals(temp2));
System.out.println(verkoop.getVerkoopLijst().first().compareTo(temp2));
System.out.println(verkoop.getVerkoopLijst().contains(temp2));
returns this:
22106622
22106622
true
0
false
Now my question would be how this is even possible?
Edit:
public class Ticket implements Comparable{
private int rijNr, stoelNr;
private TicketType ticketType;
private Boeking boeking;
public Ticket(Boeking boeking, TicketType ticketType, int rijNr, int stoelNr){
//setters
}
#Override
public int hashCode(){
return boeking.getBoekingDatum().hashCode();
}
#Override
#SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
public boolean equals(Object o){
Ticket t = (Ticket) o;
if(this.boeking.equals(t.getBoeking())
&&
this.rijNr == t.getRijNr() && this.stoelNr == t.getStoelNr()
&&
this.ticketType.equals(t.getTicketType()))
{
return true;
}
else return false;
}
/*I adjusted compareTo this way because I need to make sure there are no duplicate Tickets in my treeset. Treeset seems to call CompareTo() to check for equality before adding an object to the set, instead of equals().
*/
#Override
public int compareTo(Object o) {
int output = 0;
if (boeking.compareTo(((Ticket) o).getBoeking())==0)
{
if(this.equals(o))
{
return output;
}
else return 1;
}
else output = boeking.compareTo(((Ticket) o).getBoeking());
return output;
}
//Getters & Setters
On compareTo contract
The problem is in your compareTo. Here's an excerpt from the documentation:
Implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y.
Your original code is reproduced here for reference:
// original compareTo implementation with bug marked
#Override
public int compareTo(Object o) {
int output = 0;
if (boeking.compareTo(((Ticket) o).getBoeking())==0)
{
if(this.equals(o))
{
return output;
}
else return 1; // BUG!!!! See explanation below!
}
else output = boeking.compareTo(((Ticket) o).getBoeking());
return output;
}
Why is the return 1; a bug? Consider the following scenario:
Given Ticket t1, t2
Given t1.boeking.compareTo(t2.boeking) == 0
Given t1.equals(t2) return false
Now we have both of the following:
t1.compareTo(t2) returns 1
t2.compareTo(t1) returns 1
That last consequence is a violation of the compareTo contract.
Fixing the problem
First and foremost, you should have taken advantage of the fact that Comparable<T> is a parameterizable generic type. That is, instead of:
// original declaration; uses raw type!
public class Ticket implements Comparable
it'd be much more appropriate to instead declare something like this:
// improved declaration! uses parameterized Comparable<T>
public class Ticket implements Comparable<Ticket>
Now we can write our compareTo(Ticket) (no longer compareTo(Object)). There are many ways to rewrite this, but here's a rather simplistic one that works:
#Override public int compareTo(Ticket t) {
int v;
v = this.boeking.compareTo(t.boeking);
if (v != 0) return v;
v = compareInt(this.rijNr, t.rijNr);
if (v != 0) return v;
v = compareInt(this.stoelNr, t.stoelNr);
if (v != 0) return v;
v = compareInt(this.ticketType, t.ticketType);
if (v != 0) return v;
return 0;
}
private static int compareInt(int i1, int i2) {
if (i1 < i2) {
return -1;
} else if (i1 > i2) {
return +1;
} else {
return 0;
}
}
Now we can also define equals(Object) in terms of compareTo(Ticket) instead of the other way around:
#Override public boolean equals(Object o) {
return (o instanceof Ticket) && (this.compareTo((Ticket) o) == 0);
}
Note the structure of the compareTo: it has multiple return statements, but in fact, the flow of logic is quite readable. Note also how the priority of the sorting criteria is explicit, and easily reorderable should you have different priorities in mind.
Related questions
What is a raw type and why shouldn't we use it?
How to sort an array or ArrayList ASC first by x and then by y?
Should a function have only one return statement?
This could happen if your compareTo method isn't consistent. I.e. if a.compareTo(b) > 0, then b.compareTo(a) must be < 0. And if a.compareTo(b) > 0 and b.compareTo(c) > 0, then a.compareTo(c) must be > 0. If those aren't true, TreeSet can get all confused.
Firstly, if you are using a TreeSet, the actual behavior of your hashCode methods won't affect the results. TreeSet does not rely on hashing.
Really we need to see more code; e.g. the actual implementations of the equals and compareTo methods, and the code that instantiates the TreeSet.
However, if I was to guess, it would be that you have overloaded the equals method by declaring it with the signature boolean equals(Ticket other). That would lead to the behavior that you are seeing. To get the required behavior, you must override the method; e.g.
#Override
public boolean equals(Object other) { ...
(It is a good idea to put in the #Override annotation to make it clear that the method overrides a method in the superclass, or implements a method in an interface. If your method isn't actually an override, then you'll get a compilation error ... which would be a good thing.)
EDIT
Based on the code that you have added to the question, the problem is not overload vs override. (As I said, I was only guessing ...)
It is most likely that the compareTo and equals are incorrect. It is still not entirely clear exactly where the bug is because the semantics of both methods depends on the compareTo and equals methods of the Boeking class.
The first if statement of the Ticket.compareTo looks highly suspicious. It looks like the return 1; could cause t1.compareTo(t2) and t2.compareTo(t1) to both return 1 for some tickets t1 and t2 ... and that would definitely be wrong.

Categories

Resources