is there any way to delete an object while creating it? - java

I'm practising towards finals and I have faced this question -
Given the following code, is there any way that the there is an implementation of class A such that at the end it will print 5 in one run of the program, then in other run of the program 4, then another run 3...till 0.
Can assume that it's deterministic so functions will generate always the same results.
Can't delete any code in class A and not in the main, and able only to edit A class.
public class A {
int i, j;
public A(int i, int j) {
this.i = i;
this.j = j;
}
public static void main(String[] args) {
Set<A> s = new LinkedHashSet<>();
s.add(new A(3,1));
s.add(new A(1,3));
s.add(new A(3,1));
s.add(new A(3,1));
s.add(new A(2,1));
System.out.println(s.size());
}
}
I was thinking to add kind of static HASHMAP and every time I create an object I will add it to there and I will check if one key already exists then I would like to "not create" the object if one with same values already exists... but not able to implement it.

You're going to want to implement equals and hashcode into class A. You should implement them in such a way that it will cause collisions when adding items into Set s.
By default, it should print out the number 5.
But, if we make the following edit:
public class A {
int i, j;
public A(int i, int j) {
this.i = i;
this.j = j;
}
#Override
public boolean equals(Object obj) {
// First we check if the object is null
// Then we check if it's the same class as this one
if(obj == null || obj.getClass()!= this.getClass()) {
return false;
}
A objectA = (A) obj;
if(this.i == objectA.i) {
return true;
} else {
return false;
}
}
#Override
public int hashCode()
{
return this.i;
}
This particular implementation will result in printing out '3'. This is because we set it so that the hashcode is equal to i. Therefore when we add two instances of class A to the set, they will collide.
In our case, when instances of class A are added, the values for i are 3, 1, 3, 3, 2, there are 3 unique values of i (3, 1, 2), so therefore it will print 3.
From here you can come up with different implementations to get different values.

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.

HashSet inserts 2 elements which are equal

I was recently working on a basic task which involved a set and I stumbled upon a curious problem. I have the following class:
public static class Quadruple {
int a;
int b;
int c;
int d;
Map<Integer, Integer> histogram;
public Quadruple(int a, int b, int c, int d) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.histogram = new HashMap<>();
histogram.put(a, histogram.get(a) == null ? 1 : histogram.get(a) + 1);
histogram.put(b, histogram.get(b) == null ? 1 : histogram.get(b) + 1);
histogram.put(c, histogram.get(c) == null ? 1 : histogram.get(c) + 1);
histogram.put(d, histogram.get(d) == null ? 1 : histogram.get(d) + 1);
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Quadruple)) {
return false;
}
Quadruple q = (Quadruple) obj;
return q.histogram.equals(this.histogram);
}
#Override
public int hashCode() {
return Objects.hash(a, b, c, d);
}
When I initialize 2 objects of this type like so:
Quadruple q1 = new Quadruple(1, 1, 1, 2);
Quadruple q2 = new Quadruple(1, 1, 2, 1);
q1.equals(q2) returns true but both objects can be added separately to a HashSet.
Now I understand from the contract of HashSet, that if the object you are trying to add equals() an already present object, it should be considered present and nothing should be done.
I've managed to circumvent this issue by using LinkedList and checking if the list contains() the object before adding it, which seems to work accordingly.
My question is, is this behavior normal, as I checked the underlying implementation and saw that the HashMap which is used in HashSet actually checks the values with equals(). Is there something I might be missing?
Your equals method compares histogram, but your hashCode computes the hash from 4 other fields instead. Your implementation of hashCode method violates the contract between equals and hashCode, which says that if two object are equal, they have to have the same hash.
If you look at the implementation of Objects.hash you will get to this code:
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
And as you can see in the loop, the order of arguments passed to Object.hash matters.
As for the solution, I can't really see a reason to have fields other than histogram at all. Either way, given the implementation of your equals method, your hashCode method should look like this:
#Override
public int hashCode() {
return histogram.hashCode();
}

Calling a 'dynamic' Object of a HashMap

I just came to the problem where I want to call a function of an Object inside a HashMap. I already searched it up and found one thread but sadly I don't understand it.
So here's my code
public class Seat {
//some attributes
public int getNumber() {
return number;
}
public boolean isReserved() {
return status;
}
}
public class Hall {
private HashMap mySeats;
public HashMap getMeinePlaetze() {
return meinePlaetze;
}
public void createSeats() {
for (int i = 1; i <= this.getnumberOfSeats(); i++) {
this.getMySeats().put(i, new Seat(i, 1));
}
}
}
public class Main {
Hall h1 = new Hall(...);
h1.createSeats();
h1.getMySeats().get(2).isReserved(); //How do I have to write this to work out?
}
I hope my intend is reasonable. Feel free to correct me if my code sucks. I already apologize for it.
Thank you very much.
Since version 5, Java has a feature called Generics. You'll find a lot about generics on the web, from articles, blog posts, etc to very good answers here on StackOverflow.
Generics allows Java to be a strongly typed language. This means that variables in Java can not only be declared to be of some type (i.e. HashMap), but also to be of some type along with one or more generic type parameters (i.e. HashMap<K, V>, where K represents the type parameter of the keys of the map and V represents the type parameter of the values of the map).
In your example, you are using a raw HashMap (raw types are types that allow for generic type parameters to be specified, however the developer has not specified them). Raw types are considered bad practice and are highly error-prone, as you are experiencing right now.
HashMap allows two generic type parameters (one for the keys and another one for the values). In your case, you are using Integer for the keys and Seat for the values. Put into simple words, you are mapping integers to seats, or you can also say that your map is a map of integers to seats.
So, inside you Hall class, you should define your map with its generic type parameters:
private Map<Integer, Seat> mySeats = new HashMap<>();
Then, this code:
h1.getMySeats().get(2)
will return an instance of type Seat, because your map already knows that all its values are of type Seat.
So your code:
h1.getMySeats().get(2).isReserved();
will compile fine and will work without any errors.
Please note that, apart from declaring the generic types of your map, I've also changed two additional things.
First, I've created an actual instance of HashMap by using its constructor:
mySeats = new HashMap<>()
If you don't create an instance of your type with new, there won't be any HashMap instance where to put your seats later, and you'll get a NullpointerException (try it!).
Secondly, I've changed the type of the variable from HashMap to Map. HashMap is a class, while Map is just an interface. The thing is that the HashMap class implements the Map interface, so, unless your code explicitly needs to access a method of HashMap that is not declared in the Map interface (which is almost never the case), you will be fine with the mySeats variable being of type Map<Integer, Seat> instead of HashMap<Integer, Seat>. This is called programming to the interface and is a best practice that you should embrace from the very beginning. It will save you a lot of headaches in the future.
Following my tip in the comments, I wouldn't use a Map to link a meaningful row or number to a map-key or an array-index.
So, actually I would do it this way (because you asked, what I mean with my tip):
Seat:
public class Seat {
private final int row;
private final int number;
private boolean reserved = false;
public Seat(int row, int number) {
this.row = row;
this.number = number;
}
public boolean reserve() {
if (!reserved) {
reserved = true;
return reserved;
}
return !reserved;
}
public int getRow() {
return row;
}
public int getNumber() {
return number;
}
public boolean isReserved() {
return reserved;
}
public boolean is(int row, int number) {
return this.row == row && this.number == number;
}
#Override
public int hashCode() {
int hash = 7;
hash = 23 * hash + this.row;
hash = 23 * hash + this.number;
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Seat other = (Seat) obj;
if (this.row != other.row) {
return false;
}
return number == other.number;
}
}
Hall:
public class Hall {
public final Set<Seat> seats = new HashSet<>();
public Set<Seat> getSeats() {
return Collections.unmodifiableSet(seats);
}
public void createSeats(int lastRow, int seatsPerRow) { // This is an example; in case you have different count of seats per row, you better make an boolean addSeat(int row, int number) function; boolean to check if it has been added or if the seat already exists
for (int row = 1; row <= lastRow; row++) {
for (int number = 1; number <= seatsPerRow; number++) {
seats.add(new Seat(row, number));
}
}
}
public Seat get(int row, int number) {
for (Seat seat : seats) { // or you use seats.iterator; I personally hate Iterators; it is my subjective point of view.
if (seat.is(row, number)) {
return seat;
}
}
return null;
}
public boolean reserve(int row, int number) {
Seat seat = get(row, number);
if (seat != null) {
return seat.reserve();
}
return false;
}
}
And my Test-drive:
public class TestDrive {
public static void main(String[] args) {
Hall hall = new Hall();
int lastRow = 15;
int seatsPerRow = 10;
hall.createSeats(lastRow, seatsPerRow);
boolean reserved = hall.reserve(5, 9);
System.out.println("Seat(Row=5, Number=9) is reserved: " + (reserved == hall.get(5, 9).isReserved()));
boolean reservedAgain = hall.reserve(5, 9);
System.out.println("Seat(Row=5, Number=9) cannot be reserved again: " + (reservedAgain != hall.get(5, 9).isReserved()));
}
}
h1.getMySeats().get(2).isReserved();
Please use an IDE like IntelliJ IDEA. It will tell you about mistakes like forgetting parentheses while typing.

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

Sort a list that contains a custom class

so I'm currently doing an exercise for college that has several optional parts (because we havn't done this in class yet), one of them being to use lists instead of arrays (so it'd be variable size) and another one printing the list sorted by points (I'll get to that now)
So, I have the Player.java class which looks like this.
public class Player {
String name;
String password;
int chips;
int points;
public Player(String n, String pw, int c, int p) {
name = n;
password = pw;
chips = c;
points = p;
}
public String getName() {
return name;
}
public void setName(String n) {
name = n;
}
public void setPW(String pw) {
password = pw;
}
public String getPW() {
return password;
}
public void setChips(int c) {
chips = c;
}
public int getChips() {
return chips;
}
public void setPoints(int p) {
points = p;
}
public int getPoints() {
return points;
}
}
Pretty simple, then I'm creating a List with this (in another class):
List<Player> lplayer = new ArrayList<Player>();
Adding players with this:
lplayer.add(new Player(n,pw,c,p))`
And finally reading their stats with this:
public int search_Player (String n) {
String name;
int i = 0;
boolean found = false;
while ((i <= tp) && (!found)) {
name = lplayer.get(i).getName();
if (name.equals(n)) {
found = true;
}
i++;
}
return (found == true) ? i-1 : -1;
}
public Player show_Player (int i) {
return lplayer.get(i);
}
public void list_Players() {
Collections.sort(lplayer);
int i2;
if (tp > 0) { // variable which contains number of total players
for (int i = 0;i<tp;i++) {
i2 = i+1;
System.out.println ("\n"+i2+". "+lplayer.get(i).getName()+" [CHIPS: "+lplayer.get(i).getChips()+" - POINTS: "+lplayer.get(i).getPoints()+"]");
}
}
else {
System.out.println ("There are no players yet.");
}
}
So that's basically all the code. As you can see the I already have a list_Players function but that just prints it in the order it was added. I need a way to print in sorted by the points each player has (so basically a ranking).
As you can see I'm pretty new to java so please try not to come up with a very complicated way of doing it.
I've already searched for it and found things like Collections.sort(list) but I guess that's not what I need right here.
Thank you!
You can use the public static <T> void sort(List<T> list, Comparator<? super T> c) overload in Collections - provide the comparator you need (can be just an anonymous class) - and you are all set!
EDIT:
This describes how the method works. In brief, you'll implement your call as
Collections.sort(list, new Comparator<Player>() {
int compare(Player left, Player right) {
return left.getPoints() - right.getPoints(); // The order depends on the direction of sorting.
}
});
That's it!
Collections.sort(list) could definitely by a solution for your problem. It's a way to sort your collections provided by Java. If you are writing a "real world" application (not an exercise for collage) this would be the way you doing it.
To let Collections.sort(list) works, you have to implement an interface call Comparaple. By implementing this interface, the sort will know how to order your elements.
But because it's a exercise for collage, this is perhaps a little bit to easy. If you want (or must) implement you own sorting algorithm, try first to sort a common list of numbers (1, 5, 2, 7...). You can extend such an sorting algorithm easily for your own classes.
A new approach using lambdas, that is a lot shorter to write is
myList.sort((obj1, obj2)->(condition)?1:-1);
where you can use the objects for your condition, and anything greater than 0 returned means swap (in this case if condition returns true)

Categories

Resources