Implementing an equals() method to compare contents of two 'bag' objects - java

I am working on a school assignment. The objective is to practice GUI's, clone() methods, and using/ modifying existing code. I am trying to write an equals method in the way the instructor desires-- by using a clone of the object, removing items from the bag (returns boolean based on success or failure to remove).
The bag is represented in an array, and should return true in cases such as {1,2,3} and {3,2,1}, ie order does not matter, only the number of each number present in the arrays.
Here is the issue
It works in most cases, however there is a bug in cases where the bags contain numbers as such: {1,1,2} and {1,2,2} and other similar iterations. It is returning true instead of false.
I believe it has something to do with the remove() method we are supposed to use. If i understand it correctly, it is supposed to put the value at the 'end' of the array and decrease the manyItems counter (this is a variable for number of items in the array, because array.length is by default in the constructor 10.)
The code is largely written by another person. We had to import the existing files and write new methods to complete the task we were given. I have all the GUI part done so i will not include that class, only the used methods in the IntArrayBag class.
A second pair of eyes would be helpful. Thanks.
public class IntArrayBag implements Cloneable
{
// Invariant of the IntArrayBag class:
// 1. The number of elements in the bag is in the instance variable
// manyItems, which is no more than data.length.
// 2. For an empty bag, we do not care what is stored in any of data;
// for a non-empty bag, the elements in the bag are stored in data[0]
// through data[manyItems-1], and we don�t care what�s in the
// rest of data.
private int[ ] data;
private int manyItems;
public IntArrayBag( )
{
final int INITIAL_CAPACITY = 10;
manyItems = 0;
data = new int[INITIAL_CAPACITY];
}
public IntArrayBag clone( )
{ // Clone an IntArrayBag object.
IntArrayBag answer;
try
{
answer = (IntArrayBag) super.clone( );
}
catch (CloneNotSupportedException e)
{ // This exception should not occur. But if it does, it would probably
// indicate a programming error that made super.clone unavailable.
// The most common error would be forgetting the "Implements Cloneable"
// clause at the start of this class.
throw new RuntimeException
("This class does not implement Cloneable");
}
answer.data = data.clone( );
return answer;
}
public int size( )
{
return manyItems;
}
public boolean remove(int target)
{
int index; // The location of target in the data array.
// First, set index to the location of target in the data array,
// which could be as small as 0 or as large as manyItems-1; If target
// is not in the array, then index will be set equal to manyItems;
for (index = 0; (index < manyItems) && (target != data[index]); index++)
// No work is needed in the body of this for-loop.
;
if (index == manyItems)
// The target was not found, so nothing is removed.
return false;
else
{ // The target was found at data[index].
// So reduce manyItems by 1 and copy the last element onto data[index].
manyItems--;
data[index] = data[manyItems];
return true;
}
}
//I added extra variables that are not needed to try to increase readability,
//as well as when i was trying to debug the code originally
public boolean equals(Object obj){
if (obj instanceof IntArrayBag){
IntArrayBag canidate = (IntArrayBag) obj; // i know this can be changed, this was required
IntArrayBag canidateTest = (IntArrayBag) canidate.clone(); //this was created
//as a clone because it was otherwise referring to the same memory address
//this caused items to be removed from bags when testing for equality
IntArrayBag test = (IntArrayBag) this.clone();
//fast check to see if the two objects have the same number of items,
//if they dont will return false and skip the item by item checking
if (test.size() != canidateTest.size())
return false;
//the loop will go through every element in the test bag it will
//then remove the value that is present at the first index of the test bag
for (int i = 0; (i < (test.size()) || i < (canidateTest.size())); i++){
int check = test.data[i];
//remove() returns a boolean so if the value is not present in each bag
//then the conditional will be met and the method will return false
boolean test1 = test.remove(check);
boolean test2 = canidateTest.remove(check);
if (test1 != test2)
return false;
}//end for loop
// if the loop goes through every element
//and finds every value was true it will return true
return true;
}//end if
else
return false;
}//end equals
}

I cannot see the big picture, as I havent coded GUIs in Java before, however, as far as comparing 2 int[] arrays, I would sort the arrays before the comparison. This will allow you to eliminate problem cases like the one you stated ( if sorting is possible), then apply something like:
while(array_1[index]==array_2[index] && index<array_1.length)
{index++;}
and find where did the loop break by checking the final value of index

Is it explicitly stated to use clone? You can achieve it easily by overriding the hashCode() for this Object.
You can override the hashCode() for this object as follows:
#Override
public int hashCode() {
final int prime = 5;
int result = 1;
/* Sort Array */
Arrays.sort(this.data);
/* Calculate Hash */
for(int d : this.data) {
result = prime * result + d;
}
/* Return Result */
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || this.getClass() != obj.getClass()){
return false;
}
return false;
}
If you want to continue using your implementation for equals to compare test and CandidateTest then also you can compute unique hashes and make decision based on the results.
Here is the code snippet:
/* Assuming that you have put size comparison logic on top
and the two objects are of same size */
final int prime = 31;
int testResult = 1;
int candidateTestResult = 1;
for(int i = 0; i < test.size(); i++) {
testResult = prime * testResult + test.data[i];
candidateTestResult = prime * candidateTestResult + candidateTest.data[i];
}
/* Return Result */
return testResult == candidateTestResult;

I believe the problem is in this line:
for (int i = 0; (i < (test.size()) || i < (canidateTest.size())); i++){
The problem here is that test and canidateTest are the clones that you made, and you are removing elements from those bags. And any time you remove an element from the bag, the size will decrease (because you decrease manyItems, and size() returns manyItems). This means you're only going to go through half the array. Suppose the original size is 4. Then, the first time through the loop, i==0 and test.size()==4; the second time, i==0 and test.size()==3; the third time, i==2 and test.size()==2, and you exit the loop. So you don't look at all 4 elements--you only look at 2.
You'll need to decide: do you want to go through the elements of the original array, or the elements of the clone? If you go through the elements of the clone, you actually never need to increment i. You can always look at test.data[0], since once you look at it, you remove it, so you know test.data[0] will be replaced with something else. In fact, you don't need i at all. Just loop until the bag size is 0, or until you determine that the bags aren't equal. On the other hand, if you go through the elements of this.data (i.e. look at this.data[i] or just data[i]), then make sure i goes all the way up to this.size().
(One more small point: the correct spelling is "candidate".)

Maybe you should try SET interface
view this in detail :http://www.tutorialspoint.com/java/java_set_interface.htm
A set object cannot contains duplicate elements, so it's suitable for your assignment than build your own class.
For example:[1,1,2] and [1,2,2]
you can use this to test whether they are equal
arr1 = {1,1,2}
arr2 = {1,2,2}
Set<Integer> set = new HashSet<Integer>();
for(int i : arr1){//build set of arr1
if(set.contains(i)==false){
set.add(i)
}
}
for(int i:arr2){
if(set.contains(i)==false){
System.out.println('not equal');
break;
}
}
Hope this is helpful.

Related

Recursive function that returns a count of elements with the specified value in a linked list

I am working on a function, countH(), that is supposed to count the amount of times a given number appears in a linked list. For some reason, I cannot get this to work recursively. I have tried a number of different solutions but I guess I can't get something in the correct place. Sorry if I am asking the question poorly, I struggle to understand recursion formatting sometimes.
Here is the function:
public int count(int i) {
return countH(first, i);
}
private int countH(Node front, int i) { // TODO
int cter = 0;
if (front.next==null) {
return 0;
}
if(front.item == i)
cter++;
return countH(front, cter);
}
This is a late version of my code, I'm sure it was a bit better before I messed with it a bunch to try to get it to work
Thanks!
Every recursive implementation consists of two parts:
base case - that represents a simple edge-case for which the outcome is known in advance. For this task, the base case is a situation the given Node is null. Think about it this way: if a head-node is not initialed it will be null and that is the simplest edge-case that your method must be able to handle. And return value for the base case is 0.
recursive case - a part of a solution where recursive calls a made and where the main logic resides. In the recursive case, you need to check the value of a current node. If it matches the target value, then the result returned by the method will be 1 + countH(cur.next, i), otherwise it will be a result of the subsequent recursive call countH(cur.next, i).
Base case is always placed at the beginning of the method, followed by a recursive case.
And when you are writing a recursive part, one of the most important things that you have to keep in mind is which parameters change from one recursive call to another, and which remains the same. In this case, changes only a Node, the target value i remains the same.
public int count(int i) {
return countH(first, i);
}
private int countH(Node cur, int i) { // `front` replaced by `cur`
if (cur == null) { // not cur.next == null (it'll fail with exception if the head-node is null)
return 0;
}
// int cter = 0; // this intermediate variable isn't needed, it could be incremted by 1 at most during the method execution
// if(cur.item == i)
// cter++;
// return countH(cur, cter); // this line contains a mistake - variable `i` has to be passed as a parameter and `cter` must be added to the result returned by a recursive call
return cur.item == i ? 1 + countH(cur.next, i) : countH(cur.next, i);
}
Suggestion
Follow the comments in the code. I've left your original lines in place so that will be easier to compare solutions. Also, always try to come up will reasonable self-explanatory names for variables (as well as methods, classes, etc). For that reason, I renamed the parameter front to cur (short for current), because it's meant to represent any node, not first or any other particular node.
Side note
This statement is called a ternary operator or inline if statement
cur.item == i ? 1 + countH(cur.next, i) : countH(cur.next, i);
And it's just a shorter syntax for the code below:
if (cur.item == i) {
return 1 + countH(cur.next, i);
} else {
return countH(cur.next, i);
}
You could use either of these constructs in your code. The difference is only in syntax, both will get executed in precisely the same way.
In a linked list, you should have one element and from that you get the value and the next element. So your item could look like (I am omitting getters, setters and exception handling):
class Item {
Object value;
Item next;
}
Then your counter for a specific value could look like
int count(Object valueToCount, Item list) {
int result = 0;
if (valueToCount.equals(list.value)) {
result++; // count this value
}
if (value.next != null) {
result += count(valueToCount, value.next) // add the count from remainder of the list
}
return result;
}
public int count(int i) {
return countH(first, i);
}
private int countH(Node front, int i) { // TODO
if(front==null) {
return 0;
}
if (front.item == i) {
return 1 + countH(front.next, i);
} else {
return countH(front.next, i);
}
}

Passing method of one class into another [duplicate]

This question already has answers here:
Passing a method from another class
(4 answers)
Closed 5 years ago.
My problem is that I need to getSymbol from Element class.
I would normally establish an object in PeriodicTable like this:
Element e = new Element();
then use e.getSymbol within method in order to use it for comparison.
So, in order to complete first task and print entire list of elements, I declared an array within PeriodicTable like this:
Element[] objects = new Element[ARRAY_SIZE];
I'm guessing I declared it correctly, as it does run entire list of elements.
Again, I am having problems getting getSymbol into my method in PeriodicTable.
Any helpful suggestions, please?
For this method, a user will input a symbol for an element. The method will search for the element and return its index (in the array). Then, it will use the index to display that single element and all of its other information, using the toString method from the Element class.
public int searchBySymbol(String sym)
{
int index = 0;
boolean found = false;
for (int i = 0; i < objects.length; i++)
{
objects[i] = objects.getSymbol;
}
while (index < objects.length && !found)
{
if (objects[index].equals(sym))
{
found = true;
}
else
{
index++;
}
}
if(found)
{
System.out.println("Found at position: " + index);
System.out.println(objects[index].toString());
}
else
{
System.out.println("Not found");
}
}
You definitely don't need two loops in there first of all, there are two solutions to this:
(Recommended) If searching Elements by symbol will be the your main way of looking up Elements, consider using a HashMap to contain the data rather than an Element array as HashMaps allow look up of objects by a key e.g. HashMap<String, Element>. Lookup the HashMap API or check this example: http://beginnersbook.com/2013/12/hashmap-in-java-with-example/
(Quick fix) Rather than using two loops to get the field and compare, in Java it is good practice to define accessor methods such as getSymbol() and return the field rather than directly accessing it. Using this method you can simplify your code into...
for (Element e : objects) {
if (e.getSymbol().equals(sym) {
return true;
}
}
//return false after the loop omits the need for an explicit boolean variable`
Edit: Usual for loop construct for index access. The index number is essentially tracked by the iterator variable int i so you do not need a separate variable to track it.
for (int i = 0; i < objects.length; i++) {
if (objects[i].getSymbol().equals(sym)) {
//print i to show index number
//print objects[i].toString();
return true;
}
}
//print not found...
return false;

LinkedList can not be converted to boolean, what am i doing wronge?

I am currently learning Java. Today I am making a little program where I input numbers and the program shall write if they are sorted or not.
I think I got the logic right, but I got a little error that I can't handle.
package inlamningsuppgift_arSorterad;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Scanner;
public class ifSorted {
public static void main(String[] arg) {
LinkedList a = new LinkedList();
Scanner sc = new Scanner(System.in);
System.out.println("Input your numbers, end with the letter \\n");
while (sc.hasNextDouble())
a.add(sc.nextDouble());
if (ifSorted(a))
System.out.println("List is sorted");
else
System.out.println("List is not sorted");
}
private static boolean ifSorted(LinkedList a) {
Collections.sort(a);
return a;
}
}
make this substitution! it work with Java8:
1- a.stream().sorted().collect(Collectors.toList() create a new sorted list
2- .equal(a) the new list comes compares the current
private static boolean ifSorted(LinkedList a) {
return a.stream().sorted().collect(Collectors.toList()).equals(a);
}
Lets take a look at your aerSorterat method.
private static boolean aerSorterat(LinkedList a) {
Collections.sort(a);
return a;
}
private static boolean means that your method will return a boolean which is either true or false .You inserted list [a] then returned [a] .No boolean .With your code You don't need that method.However you must cut the if else statement out of the loop so that after the user inserts a String for ex: out. It checks your list out side the loop.You can use the method if you want by inserting your if else statement in it and returning true or false then calling that method in the main method using ifsorted.aerSorterat(a);
You are actually trying to sort your list there with Collections.sort(a), but if you want to see if your values are sorted, you can do it e.g. with a loop like this:
private static boolean isSorted(List<Double> list) {
return ascending(list) || descending(list);
}
If you have to check both ways, you easy do that with both methods connecting with an ||, which is an logical or.
The single methods simply check if all values in a list are greater (ascending) oder lesser (descending) then their predecessors.
private static boolean ascending(List<Double> list) {
for (int i = 1; i < list.size(); i++)
if (list.get(i - 1) > list.get(i))
return false;
return true;
}
private static boolean descending(List<Double> list) {
for (int i = 1; i < list.size(); i++)
if (list.get(i - 1) < list.get(i))
return false;
return true;
}
If one of the values doesn't fit the premise, it simply returns false. If the loop is completed and left normally, that means that all values are sorted.
But to do that, you have to give the generic parameter <Double> as a parameter to your method, otherwise you cannot compare the values with < and >. Also I use List instead of LinkedList because with that given, you can use any kind of List you want.
If you want to use other objects than numbers, you need to change it a little.
First possability is, the objects you want to use have to implement the Comparable Interface, which provides the compareTo(...) method. Which that given, you can is it e.g. like the following:
public boolean ascending(List<YourObject> list) {
for (int i = 1; i < list.size(); i++)
if (list.get(i-1).compareTo(list.get(i)) > 0)
return false;
return true;
}
Simply swap the operator for descending. This e.g. can be used with a list of Strings.

Iterator stack hasNext() not returning true

I'm trying to iterate over an Object array. Using the next() method works so I'm guessing that my iterator class and constructors are working.
For some reason i'm not getting any output while the hasNext() method is running.
Iterator it = hej.iterator();
Object j = it.next();
System.out.println(j);
while(it.hasNext()){
Object i = it.next();
System.out.println(i + " ");
}
With "hej" being my Object array.
My code for the next(); and hasNext() methods are as follows:
public class StackIterator implements Iterator<Object>{
// fields
private int element = 0;
private final Object[] elements;
private final int max;
// constructor
public StackIterator(Object[] values, int maxIndex) {
elements = values;
max = maxIndex;
}
// methods
public boolean hasNext() {
return element < max;
}
public Object next() {
return elements[element++];
}
}
The file that constructs the Object Array and the Object Array depends on an interface:
public interface Stack {
int size();
boolean isEmpty();
void push(Object element);
Object pop();
Object peek();
Iterator<Object> iterator();
}
The methods are then explained in another file:
public class StackExample implements Stack {
// fields
int length = 0;
Object[] arr;
// constructor
public StackExample() {arr = new Object[length];}
// method returns size of object array
public int size() {
return arr.length;
}
// method checks if object is empty
public boolean isEmpty() {
boolean result = false;
if (arr.length == 0){
result = true;
}
return result;
}
// method for push
public void push(Object element) {
newBiggerObj();
arr[0] = element;
}
// returns the first object of the stack
public Object pop() {
Object[] temp = new Object[arr.length-1];
Object first = arr[0];
for (int i = 0; i<arr.length-1; i++){
temp[i] = arr[i+1];
}arr = temp;
return first;
}
// returns the object on top of stack
public Object peek() {
if (isEmpty()){
try{
throw new Exception("Stack empty, can't peek!");
}
catch(Exception e){
return e.getMessage();
}
}
else {
Object first = arr[0];
return first;
}
}
// method for push method
private void newBiggerObj(){
Object[] temp = new Object[arr.length+1];
for (int i = 0; i<arr.length; i++){
temp[i+1] = arr[i];
}
arr = temp;
}
public String toString(){
String str = "";
for (int i = 0; i < arr.length; i++){
str = str + arr[i] + " , ";
}return str;
}
public Iterator<Object> iterator() {
return new StackIterator(arr, length);
}
}
What bothers me is that the method Iterator is within itself returning an instance of the class Stack Iterator. Which i posted above. So my real problem seems to be that my fields are not being given any value, since I am not myself giving the any values within the constructor.
My main method in which I'm testing all of this is as follows:
public class Teststack {
public static void main(String[] args){
// new instane of class StackExample
StackExample hej = new StackExample();
// test for the different methods
System.out.println(hej.isEmpty());
System.out.println(hej.size());
hej.push(4);
hej.push("hej");
hej.push(6);
hej.push(5);
System.out.println(hej.size());
System.out.println(hej.peek());
System.out.println(hej.pop());
System.out.println(hej.toString());
System.out.println(hej.isEmpty());
System.out.println("Testing Iterator: ");
// test for iterator
Iterator it = hej.iterator();
Object j = it.next();
System.out.println(j);
while(it.hasNext()){
Object i = it.next();
System.out.println(i + " ");
}
}
}
In your StackExample class, I don't see the length variable being updated when elements are pushed or popped. Due to this, length will always be 0 and calls to it.hasNext() will always return false.
You don't need to pass the length as a separate argument. You can find the array's length in the StackIterator constructor and use it.
Also note that since you're creating a new array on every push and pop, the iterator returned by StackExample#iterator() will become stale after every push/pop since it will work on an old copy/state of the stack.
The problem is here:
public Iterator<Object> iterator() {
return new StackIterator(arr, length);
}
length field is never changed, so its value is always 0. You can change the code to this:
public Iterator<Object> iterator() {
return new StackIterator(arr, arr.length);
}
Also, before retrieving elements from the iterator, you should always call it.hasNext. The fact you did this:
Iterator it = hej.iterator();
Object j = it.next();
And worked was just pure luck.
Apart of this, I can sense you have a bad design on your stack implementation. Here are some hints to improve your code:
The inner array should be initialized with a default size different than 0. E.g. 10 (as done in java.util.ArrayList implementation).
You should avoid creating a new array when adding (push) or removing (pop) an element from your stack. Instead of this, you should use the length field to control how many elements are in your stack.
The value of the new size should be based on another formula rather than array.length + 1. For example, try using something like int newSize = array.length / 2 * 3;.
Resize the inner array only when necessary. When calling push, do it only if you precisely need to increase the size of the array. When calling pop, do it if the current length of the array (this is, array.length) is far greater than the value of length field of your class.
Never forget to update the value of length on push and pop methods.
Couple of issues:
You are calling Object j = it.next(); after creating iterator and then check for hasNext. You are incrementing the element index. Hence if you just have one element, you wont enter the while loop. In addition, if your custom datastructure is empty i.e. array has no elements then you are prone to ArrayIndexOutOfBoundException.
You will always iterate and print n-1 elements instead to n elements.
Once you iterated, then your pointer will always point to last element and never get resetted. So very next time you wont be able to iterate over your elements. Its a one time iterator.
Try not to call
Object j = it.next() statement, but just while cycle. Seems you have an array of just 1 element.
There are a number of problems with this code:
In the StackIterator constructor there is no bounds checking on maxIndex. Callers can pass in a number greater than values.length, less that 0, etc.
In the next method, there is no check of the end condition, either directly or by calling hasNext(). Callers can keep calling next() and see elements beyond max or even get an ArrayIndexOutOfBoundsException, when they should be getting a NoSuchElementException.
The Stack class never increments or decrements its length field when elements are pushed or popped.
The Stack class tracks the length separately from the array, even though it always resizes the array on every push or pop, but Java arrays already know their size. (But see the next item.)
The Stack class resizes the array on every push or pop, which is very inefficient. Typically classes like this only resize the array when necessary, allowing 'slack' space, to give amortized constant time performance (see ArrayList). If you do this, however, it is necessary to null out popped items to avoid unintentional object retention.
The Stack adds and removes elements at the beginning of the array. This is incredibly inefficient since it means a O(n) reshuffling must be done on every push or pop.
The peek() method takes into account the possibility that the Stack may be empty, but the pop() method does not. A pop() on an empty Stack will throw an ArrayIndexOutOfBoundsException.
Stack is not a generic class. It holds Object. Users of the Stack will have to cast the return values from peek() or pop(), and it isn't type safe. In your example, you show a stack that is a heterogeneous mixture of String and Integer. This is a very Java 1.2 way of doing things, and while it isn't necessarily wrong, you should consider parameterizing Stack.

Calling function from several vectors ordered by element value

I have several vectors of different elements but all extending a class which has a specific function, lets say for example
Vector<classone> one;
Vector<classtwo> two;
Vector<classthree> three;
and classone, classtwo and classthree extend Number, and number has two functions:
doThing()
getValue()
And what i want is to call doThing in the order of the getValues received from all the vectors.
One cheap solution would be to concatenate all the vectors in a single Vector, sort it by value and iterate to call the function, but that makes me have to create a huge new vector, occupying new ram, and since the doThing will happen 60 times a second, if the vectors become big, it might be an overkill, i dont really want to create a new vector just to sort it, is there any other solution using the already existing vectors?
Its Java btw.
If one, two and three are sorted, you could create an custom iterator that checks for a given set of lists what the smallest value at the current position is and proceed there.
Should look similar to this (not tested):
class MultiListIterator {
List<Number>[] lists;
int[] positions;
MultiListIterator(List<Number>... lists) {
this.lists = lists;
positions = new int[lists.length];
}
boolean hasNext() {
for (int i = 0; i < lists.length; i++) {
if (positions[i] < lists[i].length) return true;
}
return false;
}
Number next() {
int bestIndex = -1;
Number bestNumber = null;
for (int i = 0; i < lists.length; i++) {
var p = positions[i];
if (p >= positions[i].length) continue;
Number n = lists[i].get(p);
if (bestNumber == null || n.getValue() < bestNumber.getValue()) {
bestIndex = i;
bestNumer = n;
}
}
if (bestNumber == null) throw new RuntimeException("next() beyond hasNext()");
positions[bestIndex++];
return bestNumber;
}
}
Usage:
MultiListIterator mli = new MultiListIterator(one, two, three);
while (mli.hasNext()) {
mli.next().doThing();
}
You may want to let MultiListIterator implement Iterator<Number>.
Note that Java already has a built-in class Number. Using the same name for your class might lead to a lot of confusion when you forget to import it somewhere.
Premature optimizations are generally a bad idea.
Try the method that came to mind first: creating a giant Vector1 ArrayList and sorting it. If it turns out to be a performance issue, then you can start trying new things.

Categories