OverflowError relating to compareTo - java

I have a class Item, which implements Comparable, and has a compareTo method. I want to compare the object o to other Items. I casted o to Item.
In a separate class, Inventory, I have a method for inserting items into the inventory. But I only want to insert if their product numbers are different. So I try to call the compareTo() method to compare item numbers but get a stackoverflow error.
I've tried p.compareTo(iter.next), because I want it to cycle through all of the items in the list. Sorry the formatting isn't perfect. first post here.
public class item{
public int compareTo(Object o){
result = compareTo((Product)o);
if (result < 0){
return -1;
}
else if (result == 0){
return 0;
}
else{
return 1;
}
}
}
public class ProductInventory extends Product {
private void insert(Product p){
Iterator<Product> iter = list.iterator();
if (list.size() == 0) {
list.addFirst(p);
}
while(iter.hasNext()) {
p.compareTo(iter.next());
//if (p.getNumber() != iter.next().getNumber()) {
System.out.print("RESULT:" + result);
if (result != 0) {
list.addFirst(p);
}
else {
System.out.print("DUPLICATE");
}
iter.next();
}
}
I want it to print duplicate if result = 0 (the numbers are the same), otherwise add it to list.

The compareTo method in your item class is infinitely recursing on this line:
result = compareTo((Product)o); //this is a self-call!
You want to replace that line with the implementation for your compareTo, for example:
result = this.value - that.value; //insert actual logic here

Maybe you need this:
public class ProductInventory extends Product {
private void insert(Product p) {
if (!list.contains(p)) {
list.add(0, p);
}
}
}

Related

compareTo with objects returns a false while it is true

I am trying to check whether my levelorder of my Binary Search Tree is equal to the other one. To do this, I tried to make a compareTo method. I only give equal values to the method, but it keeps on saying the condition is false. When I place breakpoints, I see that the values are still equal. I am probably not understanding it correctly. Does anyone know how to solve this?
Here is what I did, as you can see below, the compareTo returns a 1 instead of a 0:
import edu.princeton.cs.algs4.BST;
import java.util.*;
public class MyBST implements Comparable<MyBST>{
private Object e;
public MyBST(Object e){
this.e = e;
}
private Object getE(){
return e;
}
public static void main(String[] args) {
int size = 4;
Random r = new Random();
Set<Integer> tes = new LinkedHashSet<>(size);
Stack<Integer> stack = new Stack<>();
while (tes.size() < size) {
tes.add(r.nextInt(10));
}
System.out.println("possible combinations");
Set<Stack<Integer>> combos = combos(tes, stack, tes.size());
Object[] arr = combos.toArray();
List<String> d = new ArrayList<>();
for (Object s : arr) {
String b = s.toString();
b = b.replaceAll("\\[", "").replaceAll("\\]", "");
d.add(b);
}
int index = 0;
do {
BST<String, Integer> bst1 = new BST<String, Integer>();
BST<String, Integer> bst2 = new BST<String, Integer>();
String key1 = d.get(index);
String key2 = d.get(index);
key1 = key1.replaceAll(" ", "");
String[] m = key1.split(",");
key2 = key2.replaceAll(" ", "");
String[] n = key2.split(",");
System.out.println("1e order");
for (int j = 0; j < m.length; j++) {
System.out.println(m[j]);
bst1.put(m[j], 0);
}
System.out.println("2e order");
for (int j = 0; j < n.length; j++) {
System.out.println(n[j]);
bst2.put(n[j], 0);
}
System.out.println("levelorder 1e BST");
MyBST e = new MyBST(bst1.levelOrder());
MyBST y = new MyBST(bst2.levelOrder());
System.out.println(bst1.levelOrder());
System.out.println("levelorder 2e BST");
System.out.println(bst2.levelOrder());
System.out.println(e.compareTo(y) + "\n");
index++;
} while (index < arr.length - 1);
}
public static Set<Stack<Integer>> combos(Set<Integer> items, Stack<Integer> stack, int size) {
Set<Stack<Integer>> set = new HashSet<>();
if (stack.size() == size) {
set.add((Stack) stack.clone());
}
Integer[] itemz = items.toArray(new Integer[0]);
for (Integer i : itemz) {
stack.push(i);
items.remove(i);
set.addAll(combos(items, stack, size));
items.add(stack.pop());
}
return set;
}
#Override
public int compareTo(MyBST o) {
if (this.e == o.e) {
return 0;
}
else
return 1;
}
}
Here you can find the BST.java class: BST.java
And the output is something like:
The breakpoint at the compareTo method says:
When you're using the == operator you're actually checking to see if the references point to the same object in memory. From your debugging screenshot you can see that they are not. this.e points to object Queue#817 while o.e points to Queue#819.
If all you want to do is test for equality, then just override equals and hashCode. You can do it like this (rest of class omitted):
public class MyBST {
private Object e;
public MyBST(Object e) {
this.e = e;
}
public Object getE(){
return e;
}
#Override
public int hashCode() {
return Objects.hashCode(e);
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof MyBST))
return false;
MyBST me = (MyBST) obj;
if (e == null) {
if (me.e != null)
return false;
} else if (!e.equals(me.e))
return false;
return true;
}
}
Implementing Comparable is more involved since you need to check for less, equal, or greater than other instances of MyBST. Unfortunately, the only field in MyBST is an Object which does not tell you anything about its actual fields. So without specific fields with which to test you need to ensure that the Object you pass also implements Comparable. Then you can declare your class like this. Rest of class omitted.
It simply says that
MyBST is comparable.
And the object that is passed in the constructor is comparable.
class MyBST<T extends Comparable<? super T>> implements Comparable<MyBST<T>>{
private T e;
public MyBST(T e){
this.e = e;
}
public T getE(){
return e;
}
#Override
public int compareTo(MyBST<T> o) {
return e.compareTo(o.e);
}
}
The other alternative is to simply pass the actual object type and store it as such, not as Object. Then just implement Comparable in MyBST and use the appropriate fields of the passed object. Lets say the object was an Apple object, you could do this.
class Apple {
String type;
int weight;
}
class MyBST implements Comparable<MyBST> {
private Apple apple;
public MyBST(Apple apple) {
this.apple = apple;
}
#Override
public int compareTo(MyBST e) {
// this could be different depending on how you wanted
// to compare one apple to another. This comparison favors
// type over weight.
// check type - String class implements comparable
int ret = apple.type.compareTo(e.apple.type);
if (ret != 0) {
return ret;
}
// same type so check weight
if (apple.weight < e.apple.weight) {
return -1;
}
if (apple.weight > e.apple.weight) {
return 1;
}
return 0; // equals apples based on criteria
}
}
Finally, you have this.
private Object getE(){
return e;
}
A private getter is not usually very useful. Make it public.

ObjectList Java task

I have been given the following main method and must write the code for the ObjectList class. I am supposed to infer the necessary functions of the ObjectList class and write the class myself, however I am unsure exactly what I need to do to fulfill this function. Any help understanding this is greatly appreciated. This is the code I was given:
ObjectList ol = new ObjectList(3);
String s = "Im Happy";
Dog d = new Dog();
DVD v = new DVD();
Integer i = 1234;
System.out.println(ol.add(s));
System.out.println(ol.add(d));
System.out.println(ol.add(v));
System.out.println(ol.add(i));
ol.remove(0);
System.out.println(ol.add(i));
System.out.println("Is the list full? "+ isFull());
System.out.println("Is the list empty? "+ isEmpty());
System.out.println("Total number of objects in the list: " + getTotal());
Object g = ol.getObject(1);
g.bark();
It's quite simple just need to create a list of Object types using ArrayList or LinkedList in the ObjectList class and implement the function as follows
public class ObjectList{
private ArrayList<Object> objects;
public ObjectList(int size)
{
objects = new ArrayList<Object>(size);
}
public String add (Object object)
{
objects.add(object);
//anything you would like to return I'm just returning a string
return "Object Added";
}
public void remove (int index)
{
objects.remove(index);
}
public boolean isEmpty()
{
return objects.isEmpty();
}
public int getTotal()
{
return objects.size();
}
public Object getObject(int index)
{
return objects.get(index);
}
}
The isFull()is not needed since ArrayListsize can change dynamically. You can use a simple array instead of ArrayList and then implement the isFull() function.
Also when getting an object using the get getObject() function, you need to cast it to the correct type before using there function. In your code g.bark() won't work because Object doesn't have a bark function
Object g = ol.getObject(1);
//This can give a runtime error if g is not a Dog
//Use try catch when casting
Dog d = (Dog)g;
d.bark();
EDIT
This is how you would implement isFull() and other functions if using arrays instead of ArrayList but for the sake of simplicity use the ArrayList version
public class ObjectList{
private Object[] objects;
private int size = 0;
private int currentIndex = 0;
public ObjectList(int size)
{
this.size = size;
objects = new Object[size];
}
private boolean isFull() {
if(currentIndex == size)
return true;
else
return false;
}
public String add (java.lang.Object object)
{
if ( ! isFull() ) {
objects[currentIndex] = object;
currentIndex++;
return "Object added";
}
return "List full : object not added";
}
public void remove (int index)
{
if( !isEmpty() ) {
//shifting all the object to the left of deleted object 1 index to the left to fill the empty space
for (int i = index; i < size - 1; i++) {
objects[i] = objects[i + 1];
}
currentIndex--;
}
}
public boolean isEmpty()
{
if(currentIndex == 0)
return true;
else
return false;
}
public int getTotal()
{
return currentIndex;
}
public java.lang.Object getObject(int index)
{
if(index < currentIndex)
return objects[index];
else
return null;
}
}
What it seems you want to achieve is "expand" the functionality of an ArrayList and create a custom list of objects. What you could do is to create a class extending the ArrayList and define/override any other methods you want.
public class ObjectList extends ArrayList<Object> {
//constructor with initial capacity
private int length;
public ObjectList(int size){
super(size);
this.length= size;
}
public Object getObject(int index){
return this.get(index);
}
}
Now you have the add and remove functions inherited from the ArrayList class and the getObject method.
Concerning the isFull method, you can check if the size of your ObjectList class is equal to the size it was instantiated with
if(this.size() == this.length){
return true
}
return false;
And getTotal
public int getTotal(){
return this.size();
}

Get item index within an ArrayList by passing generic params

I need to create a method that return the index of an object in a list by comparing one of its fields.
I have 2 classs A and B with overrided Equals() and HashCode() methods like this:
Class A:
public class A {
private String field1;
private String field2;
//getters and setters
#Override
public boolean equals (Object o){
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
A that = (A) o;
return field1.equals(that.field1);
}
#Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + field1.hashCode();
return result;
}
}
Class B :
public class B {
private String field1;
private String field2;
//getters and setters
#Override
public boolean equals (Object o){
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
B that = (B) o;
return field2.equals(that.field2);
}
#Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + field2.hashCode();
return result;
}
}
In my main program I need to implement a generic method that returns the index of an item within an ArrayList<> of A or B.
private int getObjectIndexFromList(List<A or B> list, A or B param){
int index;
try{
index = list.indexOf(list.stream().filter(e -> e.equals(param)));
}catch (NoSuchElementException ex){
index = -1;
}
return index;
}
So my question is how to pass generic params for the method ?
I'm assuming you want to compare with either A.field1, A.field2, B.field1, or B.field1?
In that case you can use a lambda to find it in the stream. Like this:
private <T> int getObjectIndexFromList(List<T> list, Predicate<T> predicate){
int index;
try {
index = list.indexOf(list.stream()
.filter(predicate)
.findFirst()
.get());
} catch (NoSuchElementException ex){
index = -1;
}
return index;
}
Then you just use it like this:
int index = getObjectIndexFromList(listOfAs, a -> a.field1.equals("foo"));
Using streams here isn't optimal though since you're effectively traversing the list twice and checking equality on both the parametar and the sought object. Using a list iterator that keeps track of the current index is be more efficient:
private <T> int getObjectIndexFromList(List<T> list, Predicate<T> predicate){
ListIterator<T> it = list.listIterator();
while (it.hasNext()) {
// Get the item and it's index in the list
int index = it.nextIndex();
T item = it.next();
if (predicate.test(item)) {
// We found it, return the index
return index;
}
}
// We didn't find anything
return -1;
}
Here's an example of it in use:
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("foo");
list.add("bar");
list.add("foobar");
list.add("fubar");
list.add("Hello World!");
System.out.printf("String with length %s has index %s%n",
5, getObjectIndexFromList(list, s -> s.length() == 5));
}
And the output:
String with length 5 has index 3
If you have override hashcode and equals methods... why don't you make a plain call to 'List.indexOf'?
Make them extend the same abstract class (I don't know the exact problem, but if they have end in the same List is highly probable that they will end being family) and use it.
IndexOf uses 'equals' to find the index of the object so it must work...

Inserting into sorted linked list - Java

I need to maintain a sorted data structure from which items can be deleted and added. For that I decided to choose a linked list. Each data item contains a letter and some numbers such as these:
A1480, A1488, B1297, C3119
These need to be maintained in order. I have written code for it which first finds the position into the already sorted linked list where the new item needs to be added and then adds the item to its correct position, therefore maintaining the sorted linked list. It works but some items are misplaced and I am not sure how to fix my code. I do know that there is something wrong with the last loop but i am not sure what it is.
public static void main(String[] args) {
list = new LinkedList<String>();
add("C3138");
add("C3119");
add("A1488");
add("A1480");
add("A1517");
add("B1297");
add("C2597");
add("B1356");
add("C9000");
add("C3517");
add("C3729");
add("C1729");
add("B1729");
}
public static void add(String value) {
// Integer value form the string passed into the method
int valueInt = getInt(value);
// If linked list is empty, add value and return from method
if (list.size() == 0) {
list.add(value);
return;
}
// Compare this item to be added to the first item
int firstNode = getInt(list.get(0));
if (list.get(0).charAt(0) > value.charAt(0)
|| (list.get(0).charAt(0) == value.charAt(0) && firstNode > valueInt)){
list.add(0, value);
return;
}
// Compare this item to the last item
int lastNode = getInt(list.get(list.size() - 1));
if (list.get(list.size() - 1).charAt(0) < value.charAt(0) ||
(list.get(list.size() - 1).charAt(0) == value.charAt(0) && lastNode < valueInt)) {
list.add(list.size(), value);
return;
}
// add the inbetween items
int i = 1;
int tempInt = getInt(list.get(i));
while ((list.get(i).charAt(0) < value.charAt(0)
|| ((list.get(i).charAt(0) == value.charAt(0)) && (valueInt < tempInt)) && i < list.size())) {
tempInt = getInt(list.get(i));
i++;
}
list.add(i, value);
}
public static int getInt(String item) {
return Integer.parseInt(item.replaceAll("\\D", ""));
}
This code below gives me output of:
[A1480, A1517, A1488, B1729, B1297, B1356, C1729, C3729, C3517, C2597,
C3119, C3138, C9000]
and as you can see that some values in between start and finish are misplaced but start and end values are correct. Please help
Try doing this :: Change your last while condition to this::
(list.get(i).charAt(0) < value.charAt(0) || ((list.get(i).charAt(0) == value.charAt(0)) && (valueInt > tempInt)) && i < list.size())
What you are currently doing is that you are incrementing your i unless you hit a value of tempInt which is smaller than varInt, which is why A1517 gets inserted before A1488.
You shall increment your i until the value of tempInt is smaller than `varInt so that you reach the largest position the current element could achieve. I hope I could make it clear.
The working code Ideone link :: http://ideone.com/ZafWEO
Further, it would be better to check the value to i before accessing the linkedlist items. So, the condition shall look like this ::
(i < list.size() && (list.get(i).charAt(0) < value.charAt(0) || ((list.get(i).charAt(0) == value.charAt(0)) && (valueInt > tempInt)))
Take a look at Why is there no SortedList in Java?
If your values are unique, you can just use TreeSet. Generally, if you want a sorted collection, you probably don't want to start with LinkedList.
Why don't you use Comparable?
Scroll to bottom to see the class implemented Comparable
This is answer to your question:
private static LinkedList<SuperRosie> list;
public static void main(String[] args) {
// TODO Auto-generated method stub
list = new LinkedList<SuperRosie>();
add("C3138");
add("C3119");
add("A1488");
add("A1480");
add("A1517");
add("B1297");
add("C2597");
add("B1356");
add("C9000");
add("C3517");
add("C3729");
add("C1729");
add("B1729");
for (int i = 0; i < list.size(); i++)
System.out.println(list.get(i).getValue());
}
private static void add(String value) {
SuperRosie myNewRs = new SuperRosie(value);
int listSize = list.size();
// If linked list is empty, add value and return from method
if (listSize == 0) {
list.add(myNewRs);
return;
}
// Compare this item to be added to the first item
SuperRosie element = list.getFirst();
if (myNewRs.compareTo(element) <= 0) {
list.addFirst(myNewRs);
return;
}else{
if(listSize == 1){
list.addLast(myNewRs);
return;
}
}
// Compare this item to the last item
element = list.getLast();
if (myNewRs.compareTo(element) >= 0) {
list.addLast(myNewRs);
return;
}else{
if(listSize == 1){
list.addFirst(myNewRs);
return;
}
}
// add the inbetween items
int compare = 0;
for (int i = 1; i < listSize; i++) {
element = list.get(i);
compare = myNewRs.compareTo(element);
if (compare <= 0) {
list.add(i, myNewRs);
break;
}
}
}
Example to Sort comparable Linked List:
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedList<SuperRosie> list = new LinkedList<SuperRosie>();
list.add(new SuperRosie("C3138"));
list.add(new SuperRosie("C3119"));
list.add(new SuperRosie("A1488"));
list.add(new SuperRosie("A1480"));
list.add(new SuperRosie("A1517"));
list.add(new SuperRosie("B1297"));
list.add(new SuperRosie("C2597"));
list.add(new SuperRosie("B1356"));
list.add(new SuperRosie("C9000"));
list.add(new SuperRosie("C3517"));
list.add(new SuperRosie("C3729"));
list.add(new SuperRosie("C1729"));
list.add(new SuperRosie("B1729"));
Collections.sort(list);
for(SuperRosie rs : list)
System.out.println(rs.getValue());
}
}
And SuperRosie.java class implements from Comparable
public class SuperRosie implements Comparable<SuperRosie> {
private String value;
public SuperRosie(String value) {
this.value = value;
}
public String getValue() {
return value;
}
#Override
public int compareTo(SuperRosie arg0) {
int compareFirst = this.value.charAt(0) - arg0.value.charAt(0);
return compareFirst == 0 ? (Integer.parseInt(this.value.replaceAll(
"\\D", "")) - Integer
.parseInt(arg0.value.replaceAll("\\D", ""))) : compareFirst;
}
public static Comparator<SuperRosie> FruitNameComparator = new Comparator<SuperRosie>() {
public int compare(SuperRosie rosie1, SuperRosie rosie2) {
String rosieValue1 = rosie1.value.toUpperCase();
String rosieValue2 = rosie2.value.toUpperCase();
// ascending order
return rosieValue1.compareTo(rosieValue2);
// descending order
//return rosieValue2.compareTo(rosieValue1);
}
};
}
According to the performance problems, I suggest another performance solution.
private static LinkedList<String> list;
public static void main(String[] args) {
list = new LinkedList<>();
add("C3138");
add("C3119");
add("A1488");
add("A1480");
add("A1517");
add("B1297");
add("C2597");
add("B1356");
add("C9000");
add("C3517");
add("C3729");
add("C1729");
add("B1729");
for (int i = 0; i < list.size(); i++)
System.out.println(list.get(i));
}
private static void add(String value){
// don't check empty array, check to add in the first, last element.
// Each case, it works but when array has more than 1 element,
// so the above check are useless, run will cost memory, steps,....
// So don't, please do just the following
int insertIndex = 0;
for(String element : list){
if(compare(value, element) <= 0){ // or whatever compare way you want
break;
}else{
insertIndex+=1;
}
}
list.add(insertIndex, value);
}
private static int compare(String value1, String value2){
int compareFirst = value1.charAt(0) - value2.charAt(0);
return compareFirst == 0 ? (Integer.parseInt(value1.replaceAll(
"\\D", "")) - Integer
.parseInt(value2.replaceAll("\\D", ""))) : compareFirst;
}

Iterating an ArrayList to return a value

I am having trouble seeing the error of my work: I am creating an iterator (in my class LamborghiniCarLot) which will give the number of vehicles in my (ArrayList inventory;) which are rear-wheel-drive. the Lamborghini class has a method called getIsRearWheelDrive(). But attempting to call it, I get the method not found. "inventory" is the field variable holding the arraylist. Here is my code as it stands:
public int howManyAreRearWheelDrive()
{
int numberRearWheel = 0;
Iterator<Lamborghini> it = inventory.iterator();
Lamborghini inv = null;
while(it.hasNext())
{
inv = it.next();
if(inv != null)
{
if(it.getIsRearWheelDrive() == true)
{
numberRearWheel ++;
}
}
}
return numberRearWheel;
}
if(it.getIsRearWheelDrive() == true)
should be
if(inv.getIsRearWheelDrive() == true)
Instead of it.getIsRearWheelDrive() you need to use inv.getIsRearWheelDrive() since your Lamborghini class has the method. it is your iterator and an iterator does not have a getIsRearWhileDrive() method.
I would use a for loop
for(Lamborghini inv: inventory) {
if(inv.getIsRearWheelDrive()) numberRearWheel++;
}
or a Stream
public int howManyAreRearWheelDrive() {
return (int)inventory.stream().filter(inv -> inv.getIsRearWheelDrive()).count();
}

Categories

Resources