How can I wrap the int[] into an object and implement equals()? - java

I am trying to see how can I test if an element, with the same value as one already inside my Stack, is in fact in my stack.
ex.
int aa[] = {5,1};
int bb[] = {3,4};
int cc[] = {3,4};
Stack stack = new Stack();
stack.push(aa);
stack.push(bb);
System.out.println(stack.contains(cc));
>>>false
If I understand correctly this is false because the int[] objects are pointers, and becuase they are pointing at two different arrays, they are considered unequal. (From this answer)
I'm trying to wrap the int[] into an object and implement equals and hashCode, as was done in the answer to the other question but I'm getting a Cannot resolve symbol 'myArray' on o.myArray.length != myArray.length and int i = 0; i < o.myArray.length; i++. I also don't undertand why I need / where hashCode() is used.
Can someone tell me what I'm doing wrong or if there is a better solution?
import java.util.Arrays;
public class IntArray {
public int[] myArray;
public IntArray () {
myArray = new int[0];
}
public IntArray (int[] array) {
myArray = array;
}
public int[] getArray() {
return myArray;
}
public int hashCode() {
return Arrays.hashCode(myArray);
}
public boolean equals(Object o) {
if (!(o instanceof IntArray))
return false;
if (o.myArray.length != myArray.length)
return false;
else {
for (int i = 0; i < o.myArray.length; i++) {
if (myArray[i] != myArray[i]) {
return false;
}
}
return true;
}
}
}

I shall leave the question of a better way of doing this and explain what you are being told.
o is always of type Object in the equals method. The Object class does not have a myArray field - hence the error. That you checked o's an instance of IntArray previously using instanceof and that o must be at least an IntArray due to that and it defines a myArray field is not enough - you are required to cast it explictly:
((IntArray)o).myArray.length;
IntArray a = (IntArray)o;
a.myArray.length;
So basically that's it as far as that goes - you are not being explicit. I would have expected any syntax checking editor to have picked that up really so if that is approriate consider getting any one of the myriad available to avoid such mistakes.

Related

Unable to print out b.toString and c.toString

The program's purpose was to teach me how to create a character list, and practice using toString and booleanequals(object other).
public class CharList {
private char[] Array = new char[100];
private int numElements = 0;
public CharList() {
}
public CharList(String startStr){
Array=startStr.toCharArray();
}
public CharList(CharList other){
other.Array=new char[100];
}
public void add(char next) {
Array[numElements++] = next;
}
public char get(int index) {
return Array[index];
}
private int size() {
return numElements;
}
#Override
public String toString() {
String str = new String(Array);
return str;
}
public boolean equals(Object other) {
if(other == null) {
return false;
}
if(other instanceof CharList == false) {
return false;
}
else {
CharList that = (CharList) other;
return this.Array == that.Array ;
}
}
public static void main(String[] args) {
System.out.println("uncomment the code to use the charListDriver");
CharList a = new CharList();
CharList b = new CharList("Batman");
CharList c = new CharList(b);
a.add('k');
a.add('a');
a.add('t');
a.add('n');
a.add('i');
a.add('s');
System.out.println("a is :"+a.toString() +" and has " + a.size() + " chars");
System.out.println("b is :"+b.toString() +" and has " + b.size() + " chars");
System.out.println("c is :"+c.toString() +" and has " + c.size() + " chars")
System.out.println("B and A are equal : " + b.equals(a));
System.out.println("B and C are equal : " + b.equals(c));
}
}
my output is:
a is: katnis and has 6 chars
b is: and has 0 chars
c is: and has 0 chars
The main function was provided for me by my instructor. I don't understand why it is not printing out "batman".
The issue is with your constructor that takes a CharList
public CharList(CharList other){
other.Array=new char[100];
}
You see that it is setting other.Array equal to a new array of size 100.
So when you do this
CharList c = new CharList(b);
You are setting the Array of b to be a new array wiping out the array that contained the characters from "Batman".
If you fix the constructor in question to be
Array = other.Array.clone()
it'll fix the problem. I cloned the other array so that b and c aren't pointing to the exact same array. If they were then when you added chars to one, it would add chars to the other as well.
Next you'll see an issue with your size() method. It returns numElements but numElements isn't set in your constructors that take a String or a CharList so it's always 0. So be sure to set numElements in those constructors. You'll see that because of this error that when you call add on a CharList that was initialized form a String it changes the first char instead of adding it to the end.
I've only really answered the question about Batman and then size. But there are several other issues with this code as well.
What happens if someone calls add more than 100 times on a CharList initialized with default constructor
equals method is doing a reference equality check rather than making sure the chars in the arrays are identical
What happens when you call add to a CharList instantiated with String or CharList? As I noted it currently changes the char at index 0. But even if you fix that and set numElements correctly what will happen? It'll try to write past the end of the Array.
2 Things to go over (plus a 0th thing):
0)
You need to have a getArray() function. Because Array is marked private, there is no way to access it from the outside. You can write other.Array, but because Array is private, it is better practice to use a getArray function. Adding a getArray() is the way to go. (it would be simple, and look like: getArray() {return this.Array;})
1)
Your constructors that you wrote that looks like:
public CharList() {
}
public CharList(CharList other){
other.Array=new char[100];
}
is wrong.
You should change these like so:
public CharList() {
this.Array=new char[100];
}
public CharList(CharList other){
this.Array=other.Array;
}
Here, we made the empty constructor initialize to a set char length of 100. For the other, we made it so that this.Array = other.Array by using other.getArray().
Now, if you try this, it should work.
2)
Lets say you had this:
CharList batman1 = new CharList("batman");
CharList batman2 = new CharList("batman");
Then, java batman1.equals(batman2) would return false. This is because of pointers in java, and the way variable assignment works. for batman1.Array to equal batman2.array, it is not enough for their values to be equal. They also have to have to be pointing to the same thing. See Shallow copy for arrays, why can't simply do newArr = oldArr? for more info.
To fix this, we need a getArray(). Assuming we have it:
public boolean equals(Object other) {
if(other == null) {
return false;
}
if(!(other instanceof CharList)) {
return false;
}
if(other.size()!=this.size()) {
return false;
}
CharList that = (CharList) other;
for (int i=0; i<other.size(); i++) {
if (that.get(i)!=other.get(i)) return false;
}
return true;
}
I did a lot of things here. First, we cleaned up the if statements. You don't need that else at the end. Then, I implemented what is known as a shallow check. It checks if the two Arrays have the same values. If everything is the same, then return true.
If you have followed all of these steps, then it should work.

I'm getting some errors when I try to implement a generic datatype to my class

I've been trying to search, but I can't quite find the answer to my problem. I feel like I've implemented my generic datatype correctly but I'm still getting an error.
I'm doing an exercise where I'm given constructors/methods and variables (so I can't change the variable inputs for instance), and now I have to write the constructors/methods to make them work. The program creates an array (objects) that can grow by adding elements to it, and the comments above each method in the code explains what they do.
When I try to create the arrays in my two constructors, I get the error "Variable must provide either dimension expressions or an array initializer" for the empty array and "Type mismatch: cannot convert from T[] to int".
In my "add" method I get the error "Cannot invoke add(int, T) on the array type T[]" and finally in my "toArray" method I get the error "Type mismatch: cannot convert from Object[] to T[]".
The common theme seems to be that I haven't implemented the generic datatype correctly, but no matter how many times I try to search for similar questions, I can't see how what I've done have been different.
When searching, I see many people say that an array can't "grow" and to instead use an ArrayList, however there has to be a way to solve this with just an array, otherwise you can't solve this exercise.
import java.util.ArrayList;
import java.util.Arrays;
public class GrowingArray<T> {
private Object[] objects;
private int pointer;
//empty array
public GrowingArray() {
objects = new Object[];
}
//array that contains ds
public GrowingArray(T[] ds) {
objects = new Object[ds];
}
// add element e and return true
public boolean add(T e) {
pointer = 0;
objects.add(pointer++, e);
return true;
}
// return true if value d is found in the array
public boolean contains(T d) {
for(int i = 0; i <= objects.length; i++) {
if(objects[i] == d) {
}
}
return true;
}
// return the element on index i
public T get(int index) {
int i = index;
return objects[i];
}
// return first index containing d, if not found return -1
public int indexOf(T d) {
for(int i = 0; i <= objects.length; i++) {
if(d == objects[i]) {
return i;
}
}
return -1;
}
// return last index containing d, if not found return -1
public int lastIndexOf(T d) {
for(int i = objects.length; i >= 0; i--) {
if(d == objects[i]) {
return i;
}
}
return -1;
}
// return length of array
public int size() {
return objects.length;
}
// return a trimmed version of the array
public T[] toArray() {
return Arrays.copyOf(objects, objects.length);
}
}
objects = new Object[];
"Variable must provide either dimension expressions or an array initializer"
You need to pass a size. Empty brackets don't work.
objects = new Object[someInitialSize];
objects = new Object[ds];
"Type mismatch: cannot convert from T[] to int"
To copy an array use Arrays.copyOf:
objects = Arrays.copyOf(ds, ds.length);

How to decide the state of an object before starting to code?

I have the following code for displaying the sum of two consecutive element of ArrayList until the element left is one.for example:-
if i entered
1 2 3 4 5
output
3 7 5 //adding the two consecutive last one is as it is
10 5//doing the same thing
15
code
import java.util.*;
import java.lang.Integer;
class Substan{
ArrayList <Integer> list = new ArrayList <Integer> ();
ArrayList <Integer> newList = new ArrayList <Integer> ();// this will be the list containing the next sequence.
int index=0;
int sum=0;
Substan(){
Scanner read = new Scanner(System.in);
String choice;
System.out.println("Enter the elements of the array");
do{
int element = read.nextInt();
list.add(element);
System.out.println("More?");
choice = read.next();
}while(choice.equals("y") || choice.equals("Y"));
}
/* precondition- we have the raw list that user has enterd.
postcondition - we have displayed all the sublists,by adding two consecutives numbers and the last one is having one element.
*/
void sublist(){
while(noofElementsIsNotOneInList()){
index =0;
while(newListIsNotComplete()){
if(nextElementIsThere()){
sum = addTheConsecutive();
}
else{
sum = getLastNumber();
}
storeSumInNewList();
}
displayTheNewList();
System.out.println("");
updateTheLists();
}
displayTheNewList(); //as we have danger of Off By One Bug (OBOB)
System.out.println("");
}
private boolean noofElementsIsNotOneInList(){
boolean isnotone = true;
int size = list.size();
if ( size == 1){
isnotone = false;
}
return isnotone;
}
private boolean newListIsNotComplete(){
boolean isNotComplete = true;
int listSize = list.size();
int newListSize = newList.size();
if (listSizeIsEven()){
if ( newListSize == listSize/2){
isNotComplete = false;
}
}
else{
if( newListSize == (listSize/2) +1){
isNotComplete = false;
}
}
return isNotComplete;
}
private boolean listSizeIsEven(){
if ( list.size()%2 == 0 ){
return true;
}
else{
return false;
}
}
/*
we are at some index.
returns true if we have an element at (index+1) index.
*/
private boolean nextElementIsThere(){
if ( list.size() == index+1 ){
return false;
}
else{
return true;
}
}
/* precondition-we are at index i
postcondition - we will be at index i+2 and we return sum of elements at index i and i+1.
*/
private int addTheConsecutive(){
int sum = list.get(index)+list.get(index+1);
index += 2;
return sum;
}
/* we are at last element and we have to return that element.
*/
private int getLastNumber(){
return list.get(index);
}
private void storeSumInNewList(){
newList.add(sum);
}
private void displayTheNewList(){
int size = newList.size();
for ( int i=0;i<size;i++){
System.out.print(newList.get(i)+" ");
}
}
/*precondition - we have processed all the elements in the list and added the result in newList.
postcondition - Now my list will be the newList,as we are processing in terms of list and newList reference will have a new object.
*/
private void updateTheLists(){
list = newList;
newList = new ArrayList <Integer>();// changing the newList
}
public static void main(String[] args) {
Substan s = new Substan();
s.sublist();
}
}
So i have done a lot of refinement of my code but having a problem of sharing the local variables with the other methods.for example i have used index instance for storing the index and initially i thought that i will put this as not an instance but a local variable in method sublist() but as it cannot be viewed from other methods which needed to use the index like addTheConsecutive().So considering that i put the index at class level.So is it wright approach that put the variables that are shared at class level rather than looking at only the state of the object initially before coding and stick to that and never change it?
Consider this:
An object can communicate with other(s) only by sharing its attributes. So, if you need an object to read the state of another, the only way it can be done is by giving it "permission" to read the other object attributes.
You have two ways to do that:
Declaring the object attributes public, or
Creating getXXX() methods (makes sense for private attributes)
I personally prefer option two, because the getXXX() method returns the value ("state") of a particular attribute without the risk of being modified. Of course, if you need to modify a private attribute, you should also write a setXXX() method.
Example:
public class MyClass {
private int foo;
private String bar;
/*
* Code
*/
public int getFoo() {
return foo;
}
public String getBar() {
return bar;
}
public void setFoo(int foo) {
this.foo = foo;
}
public void setBar(String bar) {
this.bar = bar;
}
/*
* More code
*/
}
This way all the object attributes are encapsulated, and:
they cannot be read by any other object, unless you specifically call the appropriate getXXX() function, and
cannot be altered by other objects, unless you specifically call the appropriate setXXX() function.
Compare it with the non-abstracted version.
for (int index = 0; index < list.size(); index += 2) {
int sum = list.get(index);
if (index + 1 < list.size() {
sum += list.get(index + 1);
}
newList.add(sum);
}
Now, top-down refining the algorithm using names is a sound methodology, which helps in further creative programming.
As can seen, when abstracting the above again:
while (stillNumbersToProcess()) {
int sum = sumUpto2Numbers();
storeSumInNewList(sum);
}
One may keep many variables like sum as local variables, simplifying state.
One kind of helpful abstraction is the usage of conditions, in a more immediate form:
private boolean listSizeIsEven() {
return list.size() % 2 == 0;
}
private boolean nextElementIsThere() {
return index + 1 < list.size();
}
There's no point in declaring index at Class level since you dont want it to be a member or an instance of that class. Instead make it local to the method and pass it to other methods as argument where you want to access it.
I think you are asking the wrong question.
Your class variables make very little sense, as do many of the methods. This is mostly because:
Your class is doing too much
Your algorithm is a little odd
The class variables that you do have make much more sense passed as method parameters. Some methods need to see them, and some don't.
Your class is also a little odd, in that calling subList twice on the same class will not produce the same answer.
The code is littered with methods I don't quite see the point in, such as:
private boolean noofElementsIsNotOneInList(){
boolean isnotone = true;
int size = list.size();
if ( size == 1){
isnotone = false;
}
return isnotone;
}
Shouldn't this be:
private boolean noofElementsIsNotOneInList(){
return list.size() == 1;
}
And it makes no sense for it to use some arbitrary List, pass one in so that you know which List you are checking:
private boolean noofElementsIsNotOneInList(final Collection<?> toCheck){
return toCheck.size() == 1;
}
The same logic can be applied to almost all of your methods.
This will remove the instance variables and make your code much more readable.
TL;DR: Using lots of short appropriately named methods: good. Having those methods do things that one wouldn't expect: bad. Having lots of redundant code that makes things very hard to read: bad.
In fact, just to prove a point, the whole class (apart from the logic to read from stdin, which shouldn't be there anyway) can transformed into one short, recursive, method that requires no instance variables at all:
public static int sumPairs(final List<Integer> list) {
if (list.size() == 1)
return list.get(0);
final List<Integer> compacted = new LinkedList<>();
final Iterator<Integer> iter = list.iterator();
while (iter.hasNext()) {
final int first = iter.next();
if (iter.hasNext()) compacted.add(first + iter.next());
else compacted.add(first);
}
return sumPairs(compacted);
}
Now you could break this method apart into several appropriately named shorter methods, and that would make sense. It's sometimes more helpful to start from the other end. Sketch out the logic of your code and what it's trying to do, then find meaningful fragments to split it into. Possibly after adding unit tests to verify behaviour.
what about doing by Recursion:
public int calculateSum(List<Integer> nums) {
displayList(nums);
if (nums.size() == 1) {
return nums.get(0);
}
List<Integer> interim = new ArrayList<Integer>();
for (int i = 0; i < nums.size(); i = i + 2) {
if (i + 1 < nums.size()) {
interim.add(nums.get(i) + nums.get(i + 1));
} else {
interim.add(nums.get(i));
}
}
return calculateSum(interim);
}
public static void displayList(List<Integer> nums){
System.out.println(nums);
}
Steps:
Run calculate sum until list has 1 element
if list has more than 1 element:
iterate the list by step +2 and sum the element and put into a new List
again call calculate sum

Checking for duplicates in an int array [duplicate]

This question already has answers here:
Java Array, Finding Duplicates
(17 answers)
Closed 9 years ago.
Would this be the correct method to check whether an integer array contains duplicates? I wanted to pass in an int[] nums instead of Integer[], but couldn't get that to work.
public static boolean isUnique(Integer[] nums){
return new HashSet<Integer>(Arrays.asList(nums)).size() == nums.length;
}
You can do something like:
public static boolean isUnique(int[] nums){
Set<Integer> set = new HashSet<>(nums.length);
for (int a : nums) {
if (!set.add(a))
return false;
}
return true;
}
This is more of a short-circuit-esque approach than what you have, returning as soon as it encounters a duplicate. Not to mention it works with an int[] as you wanted. We are exploiting the fact that Set#add returns a boolean indicating whether the element being added is already present in the set.
Whether Set or sorting is irrelevant here, and sorting is more optimal, less objects.
public static boolean isUnique(int[] nums) {
if (nums.length <= 1) {
return true;
}
int[] copy = Arrays.copyOf(nums);
Arrays.sort(copy);
int old = Integer.MAX_VALUE; // With at least 2 elems okay.
for (int num : copy) {
if (num == old) {
return false;
}
old = num;
}
return true;
}
Addendum As commented slower, though saving memory.

Determine index an Object is in an array from the object itself

Is there a way for objects inside an array to detect what slot they are in? If I had a Object array, could a Object inside the array detect what cell it is in without being explicitly told?
Nope, unfortunately, how arrays work in Java is that the array simply "points" to an object. As a Java array only stores references (to objects), but any number of variables can reference the same object, so an Object has no idea where it lives in an array. In fact, the same object can be pointed to from several indices in the array!
Consider
Object o = new Object(); // The variable o has a "reference" to the Object in memory
Object[] arr = new Object[3]; // empty array to hold Object types
arr[0] = o; // the first index points to the Object we created above
arr[1] = o; // the second index points to that same object!
arr[2] = o; // still the same object! If we modified the original object (assuming it's not immutable) in any way, all the indices in this array would point to the modified object.
Hope this helps!
The fastest (easiest to write) way to iterate through an array of objects is
for (Object o : arr) {
// do something to the local variable o, which you can think of as representing each object in your array
}
No. If you need to do this, you probably have a design flaw. Why does an Object need to know where it appears in the array? If the index is of some semantic meaning or interest to the object, then the object should have an int field containing this information. If you are trying to modify the original array based on one object then you probably have a poorly-factored class somewhere, e.g. if something such as this is happening:
class A {
Object data[];
}
class B {
remove(A a, Object instance) {
// how to remove instance from a.data??
}
}
Then really B.remove should be a method of A and hence have access to data in the first place. And so forth.
Furthermore an array may just not be the right data structure. If the index has much semantic value a Map<Integer, Object> may be more appropriate, although arrays are often used to represent this when the indices are continuous from 1..n and the array is immutable. In my silly example with remove, a List would be more appropriate. Etc.
try
int i = Arrays.asList(arr).indexOf(obj);
As #Aaron_H said, no dice. I'll add that you can work around it with something like this:
public class Test {
public static void main(String[] args) {
ZenArray<IndexedString> z = new ZenArray(10);
for (int i = 0; i < z.size(); i++) {
z.set(i, new IndexedString("String " + i));
}
for (int i = 0; i < z.size(); i++) {
System.out.println("I'm at index " + z.get(i).getIndex());
}
}
}
class ZenArray<T extends ZenArray.IndexedElement> {
private Object [] a;
interface IndexedElement {
void setIndex(int i);
int getIndex();
}
public ZenArray(int size) {
a = new Object[size];
}
public void set(int i, T val) {
val.setIndex(i);
a[i] = val;
}
public T get(int i) {
return (T)a[i];
}
public int size() {
return a.length;
}
}
// An example of an indexed element implementation.
class IndexedString implements ZenArray.IndexedElement {
int i;
String val;
public IndexedString(String val) {
this.val = val;
}
public String getVal() {
return val;
}
#Override
public void setIndex(int i) {
this.i = i;
}
#Override
public int getIndex() {
return i;
}
}

Categories

Resources