How to make the java HashSet / HashMap work with any Object? - java

Is it possible to make HashSet work with any Object ?? I tried to make the Object implement
Comparable but it didn't help
import java.util.HashSet;
public class TestHashSet {
public static void main(String[] args) {
class Triple {
int a, b, c;
Triple(int aa, int bb, int cc) {
a = aa;
b = bb;
c = cc;
}
}
HashSet<Triple> H = new HashSet<Triple>();
H.add(new Triple(1, 2, 3));
System.out.println(H.contains(new Triple(1, 2, 3)));//Output is false
}
}

you need to implement equals(Object) and hashCode()
ensure that the hashcodes are equal when the objects are equal
in your example:
class Triple {
int a, b, c;
Triple(int aa, int bb, int cc) {
a = aa;
b = bb;
c = cc;
}
public boolean equals(Object arg){
if(this==arg)return true;
if(arg==null)return false;
if(arg instanceof Triple){
Triple other = (Triple)arg;
return this.a==other.a && this.b==other.b && this.c==other.c;
}
return false;
}
public int hashCode(){
int res=5;
res = res*17 + a;
res = res*17 + b;
res = res*17 + c;
//any other combination is valid as long as it includes only constants, a, b and c
return res;
}
}

For it to work properly you'll need to implement equals() and hashcode() and you'll also need to make sure they're implemented properly, following the contract set out in the Javadoc (it's perfectly possible to implement them not following this contract but you'll get bizarre results with potentially hard to track down bugs!)
See here for a description.

It already does work with any object. I suggest you need to read the Javadoc instead of guessing about the requirements.

Related

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();
}

Return an array and a variable together in main function

I have a function like that
Class Return_two{
public static void main(String args[]){
int b=0;// Declare a variable
int a []= new int[3];// Declare an array [both are return at the end of the user define function fun()]
Return_two r=new Return_two();
int result_store= r.fun(a,b);//where should I store the result meaning is it a normal variable or an array where I store the result?
}
public int [] fun (int[] array,int var)//may be this is not a good Return type to returning an array with a variable so what will be change in return type?
{
for(int counter=0;counter <array.length;counter++)
{ var=var+counter;
}
return( array,var);// Here how could I return this two value in main function?
}
}
Now, here lies my question. I want to return an array with a variable as I written above.But as I know one can return a array or a variable but not both. Or one can return one or more variable make those variable as a array element. But how can one return an array with an variable in main function?
If you want to create multiple values, wrap them in an object.
(I'm not able to come up with a meaningful name from what you have posted)
class Result {
private int[] a;
private int b;
public Result(int[] a, int b) {
this.a = a;
this.b = b;
}
//Getters for the instance variables
public int[] getA() {
return a;
}
public int getB() {
return b;
}
}
At the end of fun
return new Result(array, var);
Some best practices:
Don't declare variable names with same name as a parameter (a in fun)
In the above Result class, better to create copies on the array a to avoid mutations outside the class.
If possible, don't use arrays and use a List (this would give you a lot of flexibility)
EDIT:
Your caller will look like
Return_two r=new Return_two();
Result result = r.fun(a, b);
result.getA();//Do whatever you want to do with the array
result.getB();//Do whatever you want to do with that variable
With your current version of the (modified) code, why do you want to return the array since it is same as what you pass to the fun method? Returning only the computed var will work for you (and hence the return type can simply be int).
You can also achieve what you do in fun in one line
return (array.length * (array.length - 1)) / 2;
Wrap these properties into a object, say
Public class FunModel
{
public int[] a;
public int b;
}
then you can return an instance of `FunModel`.
Or
you can use `Tuples`
------------------
Futher Explanation
------------------
The return type here should be a model.
This model should have all that you want to return as properties.
You can return this model from your method.
public class FunModel
{
public int[] a;
public int b;
public FunModel(int[] a, int b) {
this.a = a;
this.b = b;
}
}
And the method should return a instance of this model.
public class ReturnTwo {
public static void main(String args[]){
int b=0;
int a []= new int[3];
ReturnTwo returnTwo = new ReturnTwo();
FunModel funModel = returnTwo.fun(a,b);
//other processing
}
public FunModel fun (int[] array,int tempVar)
{
FunModel temp = new FunModel(array,tempVar);
for(int counter=0;counter <array.length;counter++)
{
temp.b = temp.b + counter;
}
return temp;// you return the model with different properties
}
}

A method which accepts two integer values as input parameters and returns the boolean

This is one of the practice questions of a test:
Write a method which accepts two integer values as input parameters and returns the boolean result true if the sum of the inputs is greater than or equal to 10 (and falseotherwise)
My answer is below but I don't think it looks correct. Can anyone give me a pointer?
public class Bruh{
public static void main (String [] arg){
int a;
int b;
boolean sum = true;
if ( a+b > 10)
System.out.println ("yo");
else{
sum = false;
}
}
}
You only wrote some code in the main method but you did not create one.
In order to do that you need to actually create a method in your Bruh class like:
public static boolean isSumGreaterThan9(int a, int b){
return (a + b) > 9;
}
Than call it from the main method:
public static void main (String [] arg){
int a = 4; // or whatever
int b = 7; // or whatever
System.out.println(isSumGreaterThan9(a, b));
}
You need to put your logic into a method and change your comparison to >= as per the requirement:
public static boolean isSumGreaterThanOrEqualToTen(int a, int b) {
return (a + b) >= 10;
}

Defining a comparator for a quadratic function object

This is my assignment,
a) Write a quadraticFunction that represents a quadratic ax^2 + bx + c with int coeffients a, b, c. Provide a constructor with 3 int parameters for a, b, c. Provide a method double valueAt(double x) returns the value of this quadratic function at x. Also provide a toString method.
b) override the equals method quadraticmethod class. two quadraticfunction should be considered equal if their respective coeffiecients are equal
c) Make the function objects comparable. The compareTo should first compare 1 if equal compare b if equal compare c
d) Define a comparator class for comparing two QuadraticFunction objects. Provide two constructors: a no-argss constructor and a constructor that takes 1 double parameter. When a comparator is created by the no-args constructor, it should compare two quadraticFunction based on their values at x = 0; when a comparator is created by the constructor with a parameter x, it should compare quadraticFunction based on their values at x
Here's my code
I need help with part D, I don't know how to do some of it
public class Ex4
{
int a;
int b;
int c;
public Ex4(int x, int y, int z)
{
a = x; b=y; c=z;
}
public String toString()
{
String X="";
X= X+a+"x^2"+b+"x"+ "+" + c;
return X;
}
public double valueAt(double x)
{
return (a*x*x+b*x+c);
}
//////// Part B
public boolean equals( Ex4 qf )
{
return(this.a==qf.a && this.b==qf.b && this.c==qf.c);
}
/////Part c
// public int compareTo(Ex4 other)
// {
// if (a.equals(other.a))
// {
// if (b.equals(other.b))
// return c.compareTo(other.c);
// return b.comapreTo(other.b);
// }
// return a.compareTo(other.a);
// }
public int compareTo(Ex4 other)
{
if (a > other.a)
return 1;
else if (a < other.a)
return -1;
else if (b > other.b)
return 1;
else if (b < other.b)
return -1;
else if (c > other.c)
return 1;
else if (c < other.c)
return -1;
else
return 0;
}
////Part d
public static void main(String[] args)
{
System.out.println(new Ex3(1, -5, 6));
}
}
Also in the uncomment the area of code under part c, it says int cannot be dereferenced on line 29, 31, 32,33, and 35
Thanks for the help
You can't call methods on primitives, plain and simple.
A better option is to use Integer's static method, Integer.compare(int a, int b) to compare two ints.
First, writing a custom Comparator isn't too terribly difficult; you need to understand the basic structure of one.
Here's the idea: it reads kind of like you're writing a Comparable entity.
class CustomComparator implements Comparator<Ex4> {
#Override
public int compare(Ex4 left, Ex4 right) {
// Compare the entities as specified by the assignment
}
}
Then, you need to accept that as a constructor argument. That, I leave as an exercise to the reader.
Now, to the syntax issue: you're treating primitive int as an Integer, which does have an equals method on it. Primitives aren't objects, hence they can't be dereferenced. You'll want to use the normal equivalence operators (==, >, <) in this situation. You have this already solved in your second-defined compareTo method.
EDIT: After re-reading your requirements, I'm starting to think that your primitive fields are not the right way to go. You should:
Change your fields from int to Integer
Implement Comparable<Ex4> on your entity class
Rely on the default behavior of compareTo() for Integer; that is, your commented code should "just work" (save for the misspell when comparing against C)
Move the secondary compareTo to its own Comparator entity, as described above.
Try this
import java.util.Comparator;
public class Ex4Comparator implements Comparator<Ex4> {
private double x = 0.0;
public Ex4Comparator() {
}
public Ex4Comparator(double x) {
this.x = x;
}
#Override
public int compare(Ex4 o1, Ex4 o2) {
return Double.compare(o1.valueAt(x), o2.valueAt(x));
}
}
Also your equals method doesn't override Object's equals method. You may want to change it to something like
#Override
public boolean equals(Object o) {
if (o instanceof Ex4) {
Ex4 other = (Ex4)o;
return (a == other.a && b == other.b && c == other.c);
}
return false;
}

Have I invoked correctly?

I have been given a piece of code (the class QuestionTwo).
I am asked to state the values of a, b, and c after method mQ2 is invoked on a newly created object of class Q2.
My main.java file
package openuniversity;
public class Main
{
public static void main(String[] args)
{
QuestionTwo qt = new QuestionTwo();
qt.mQ2();
}
}
My QuestionTwo.java class file:
package openuniversity;
public class QuestionTwo
{
int a;
int b = 1;
public void mQ2()
{
{
int c;
int a = 2;
c = a;
}
{
int c;
int a;
c = 3;
a = 4;
}
a++;
}
}
I arrived at:
a: 1
b: 1
c: 3
Note I can also select 'undefined' as an answer?
So would it be 1, 1, undefined as c does not exist outside of the codeblock?
The question:
Study the following code and then select the options from the drop-down lists below that are correct about the values of a, b and c after the method mQ2 is invoked once on a newly created object of class Q2. Note that the answers you choose for a, b and c may or may not be different from each other.
public class Q2
{
int a;
int b = 1;
public void mQ2()
{
{
int c;
int a = 2;
c = a;
}
{
int c;
int a;
c = 3;
a = 4;
System.out.println("c: " + c); //correct place?
}
a++;
}
System.out.println("a: " + a + "b: " + b); // correct place?
}
Since this is homework, I'll restrict my answer to a couple of pointers.
You can verify your solution by printing out the variables after calling mQ2() (hint: you could use System.println() for that).
This is either a trick question or is partially ill-defined (hint: think about which a, b and especially c you're being asked about).
I'd suggest you first print out all the values using System.out.println() after calling mQ2, then step through the code in your mind to try to work out why the values are what they are. Remember that any variable declared is only visible within the scope ({...}s for simplicity), but these variables can have the same name as other variables so they might look like the same even if they're not.
I'd like to particularly point out that c does not exist outside that method.

Categories

Resources