I hava a Map<Integer,Double> as a field. I need to implement equals() for that given class.
How to compare the double values using a tolerance.
public class Foo {
Map<Integer, Double> data;
public Map<Integer, Double> getData() {
return data;
}
public void setData(Map<Integer, Double> data) {
this.data = data;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Foo))
return false;
Foo foo = (Foo) o;
if (this.data.size() != foo.getData().size())
return false;
Set<Integer> keySet1 = data.keySet();
Set<Integer> keySet2 = foo.getData().keySet();
// keys should same
if (keySet1.containsAll(keySet2) && keySet2.containsAll(keySet1)) {
// for the same key, the values are close
for (Integer key : keySet1) {
if (!isEntryEqual(data.get(key), foo.getData().get(key))) {
return false;
}
}
return true;
}
return false;
}
// also need to override the hashCode method
#Override
public int hashCode() {
List<Integer> keys = new ArrayList<Integer>(this.data.keySet());
return Objects.hash(keys);
}
public static final Double PRECISION = 0.0001;
private static boolean isEntryEqual(Double d1, Double d2) {
return d1 - d2 < PRECISION;
}
}
Related
I'm trying to count the number of diseases a day by using hashmap:
public static main(String[] args){
Disease cholera=new Disease("cholera");
Disease dengue=new Disease("dengue");
List<Diagnosis> diagnoses = Arrays.asList(
new Diagnosis(cholera, 0), // registered cholera on day 0
new Diagnosis(cholera, 0),
new Diagnosis(cholera, 1),
new Diagnosis(cholera, 1),
new Diagnosis(cholera, 2),
new Diagnosis(cholera, 2)
);
printFreq(diagnosis);
}
public static void printFreq(List<Diagnosis> diagnoses) {
Map<Diagnosis, Integer> hm = new HashMap();
for (Diagnosis x : diagnoses) {
if (!hm.containsKey(x)) {
hm.put(x, 1);
} else {
hm.put(x, hm.get(x) + 1);
}
}
But if I call printFreq(diagnoses) I get:{{cholera, 0}=1, {cholera, 1}=1, {cholera, 2}=1, {cholera, 0}=1, {dengue, 0}=1, {cholera, 1}=1, {cholera, 2}=1}. How can I fix this to {{cholera,0}=2,{dengue0}=1,{cholera,1}=2,{cholera,2}=2}}
I'm not allowed to change the Diagnosis or Disease class but this is how they look like:
public class Disease {
private final String name;
public Disease(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Disease disease = (Disease) o;
return name.equals(disease.name);
}
#Override
public int hashCode() {
return name.hashCode();
}
#Override
public String toString() {
return name;
}
Diagnosis:
public class Diagnosis {
private final Disease disease;
private final int day;
public Diagnosis(Disease disease, int day) {
this.disease = disease;
this.day = day;
}
public Disease getDisease() {
return disease;
}
public int getDay() {
return day;
}
#Override
public String toString() {
return "{" + disease + ", " + day + "}";
}
You can add a wrapper class to make life easier. In this code I have a wrapper class DiagnosisMetric that wraps the Diagnosis class.
Following is the new implementation of the printFreq function.
public static void printFreq(List<Diagnosis> diagnoses) {
Map<DiagnosisMetric, Long> collect = diagnoses.stream().
collect(Collectors.groupingBy(DiagnosisMetric::new, counting()));
System.out.println(collect);
}
And, following is the wrapper class. Notice that I have implemented equals and hashCode as per the requirement.
public static class DiagnosisMetric {
private Diagnosis diagnosis;
public DiagnosisMetric(Diagnosis s) {
this.diagnosis = s;
}
public Diagnosis getDiagnosis() {
return diagnosis;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DiagnosisMetric that = (DiagnosisMetric) o;
return diagnosis.getDisease().getName().
equals(that.getDiagnosis().getDisease().getName())
&& diagnosis.getDay() == that.getDiagnosis().getDay();
}
#Override
public int hashCode() {
return Objects.hash(diagnosis.getDay(),
diagnosis.getDisease().getName());
}
#Override
public String toString() {
String disease = diagnosis.getDisease().getName();
int day = diagnosis.getDay();
return "{" + disease + ", " + day + "}";
}
}
An ad-hoc solution which does not require storing the intermediate map with Diagnosis key (which cannot be used as a map key without properly implemented hashCode and equals as mentioned earlier) is like this:
use a raw list containing diagnosis.day and disease.name as a key wrapper in Collectors.groupingBy
calculate the frequencies (e.g. using Collectors.summingInt)
use Supplier<Map> to provide a tree map sorted by the list contents
print the stats
diagnoses.stream()
.collect(Collectors.groupingBy(
d -> Arrays.asList(d.getDay(), d.getDisease().getName()),
() -> new TreeMap<List<?>, Integer> (Comparator
.comparingInt((List k) -> (Integer) k.get(0))
.thenComparing((List k) -> (String) k.get(1))
),
Collectors.summingInt(d -> 1)
)) // Map<List, Integer> created here
.forEach((k, v) -> System.out.println(k + " = " + v));
Output:
[0, cholera] = 2
[0, dengue] = 1
[1, cholera] = 2
[2, cholera] = 2
To resolve this what we need to do is to override the hashCode and equals method for the Diagnosis class, like this:
#Override
public boolean equals(Object obj) {
Diagnosis diagnosis = (Diagnosis) obj;
return this.day == diagnosis.day && this.disease == diagnosis.disease;
}
#Override
public int hashCode() {
char[] charArr = this.disease.toString().toCharArray();
int sum = 0;
for (int i = 0; i < charArr.length; i++) {
sum += charArr[i];
}
return sum;
}
Also you need to override equals method of the Disease class, here is code for that:
#Override
public boolean equals(Object obj) {
Disease disease = (Disease) obj;
return this.disease.equalsIgnoreCase(disease.toString());
}
I have a created a combo box with three items. I am trying to set the selected item by index and value.
When I do setSelectedIndex () the code works well.
I am trying to set the selected item by value. So I try creating another object, with same value(variable name d), and do setSelectedItem but it fails. When I try printing out the selectedItem, it doesn't print 'C C'. It prints the previously selected item 'B B'
So how do set selectedItem by value? Do advice.
Thanks so much!
import javax.swing.JComboBox;
public class testt {
public static void main(String[] args) {
obj a = new obj("A A");
obj b = new obj("B B");
obj c = new obj("C C");
obj[] lst = { a, b, c };
JComboBox box = new JComboBox(lst);
box.setSelectedIndex(1);
System.out.println("value is:"+((obj) box.getSelectedItem()).toString());
obj d = new obj("C C");
box.setSelectedItem(d);
System.out.println(value is:"+((((obj) box.getSelectedItem()).toString());
}
}
class obj {
String value;
public obj(String value) {
this.value = value;
}
public String toString() {
return value;
}
}
Equals and Hashcode issue. The below should solve the problem.
class obj {
String value;
public obj(String value) {
this.value = value;
}
public String toString() {
return value;
}
#Override
public int hashCode() {
int hash = 5;
hash = 17 * hash + Objects.hashCode(this.value);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final obj other = (obj) obj;
if (!Objects.equals(this.value, other.value)) {
return false;
}
return true;
}
Class:
public class Variant
{
private String variant;
private String quantity;
//getters and setters
}
ArrayList:
ArrayList<Variant> variantList = getVariantsList();
Now I want to check whether variantList contains a duplicate entry of variant or not? Please note that variant having two entries with different quantity are to be considered as duplicates.
You can simply ovveride your equals method in your Variant class and provide all the rules for equality in that method.
#Override
public boolean equals(Object obj) {
..
Then you can use contains method or just pass it to a Set, that eliminates all your duplicates.
If you want variant having two entries with different quantity also considered as dup, then you can add that condition in your equals.
Override equals(Object obj) method and try to compare the object on variant and quantity.
Try to loop thru the variantList and do check for duplicity using variantList.contains(variant).
There are two things you need to do:
Override the equals() in your Variant class(minimal code below):
Please note that the below code only checks for quantity and not the variant prop. Your IDE might help you to generate the equals() as well.
#Override
public boolean equals(Object object) {
boolean isEqual = (this == object);
if(object instanceof Variant){
Variant variant = (Variant) object;
isEqual = this.quantity.equals(variant.quantity);
}else{
isEqual = false;
}
return isEqual;
}
Check if the List contains the object - which will use the equals() to check if both are equal.
for (Variant variant : variantList) {
if (variantList.contains(variant)) {
//do logic if its present
}
}
Just check one object with other objects of list
Override equals method in Variant class
#Override
public boolean equals(Object obj) {
if (obj != null) {
if (obj instanceof Variant) {
Variant temp = (Variant) obj;
return this.quantity.equals(temp.quantity); //for different quantity
} else {
return false;
}
}
return false;
}
Then check :
for (int i = 0; i < variantList.size(); i++) {
for (int j = 0; j < variantList.size(); j++) {
if (i != j) {
if (iList.get(i).equals(iList.get(j))) {
//logic when duplicate
break;
}
}
}
}
Follow the below guidelines:
Your Class Variant must override the equals method, since you define a duplicate condition based on quality hence in the equals method check for quality attribute value i.e.
public class Variant {
private String variant;
private String quantity;
public Variant(String variant, String quantity) {
this.variant = variant;
this.quantity = quantity;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((quantity == null) ? 0 : quantity.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Variant other = (Variant) obj;
if (quantity == null) {
if (other.quantity != null)
return false;
} else if (!quantity.equals(other.quantity))
return false;
return true;
}
}
Create a method which basically checking whether your list contains the duplicate entries(Variant) or not and return true and false accordingly:
private static boolean isListContainsDuplicateEntries(
ArrayList variantList) {
final List setToReturn = new ArrayList();
for (Variant v : variantList) {
if (!setToReturn.contains(v)) {
setToReturn.add(v);
} else {
return true;
}
}
return false;
}
Now, test the functionality:
public static void main(String[] args) {
Variant variant1 = new Variant("1", "100");
Variant variant2 = new Variant("2", "200");
Variant variant3 = new Variant("3", "200");
ArrayList<Variant> variantList = new ArrayList<>();
variantList.add(variant1);
variantList.add(variant2);
variantList.add(variant3);
System.out.println(Variant.isListContainsDuplicateEntries(variantList));
Output: true
You can use contains():
if (variantList.contains(**<some other Variant object>**)){
...
}
You can simply override your equals method in your Variant and try like this
List<Varient> list =getVariantsList();
System.out.println("here list size"+list.size());
Set<Varient> set = new HashSet<Varient>(list);
System.out.println("here"+set.size());
Create a varient Object:
public class Varient {
private String variant;
private String quantity;
public String getVariant() {
return variant;
}
public void setVariant(String variant) {
this.variant = variant;
}
public String getQuantity() {
return quantity;
}
public void setQuantity(String quantity) {
this.quantity = quantity;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Varient)) return false;
Varient varient = (Varient) o;
if (!quantity.equals(varient.quantity)) return false;
if (!variant.equals(varient.variant)) return false;
return true;
}
#Override
public int hashCode() {
int result = variant.hashCode();
result = 31 * result + quantity.hashCode();
return result;
}
}
Here is your main Program;
public class Test {
public static void main (String [] args){
// getVariantsList() here your list
List<Varient> list =getVariantsList();
Set<Varient> set = new LinkedHashSet<Varient>(list);
}
}
public class Variant {
private String variant;
private String quantity;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((variant == null) ? 0 : variant.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Variant other = (Variant) obj;
if (variant == null) {
if (other.variant != null)
return false;
} else if (!variant.equals(other.variant))
return false;
return true;
}
public String getVariant() {
return variant;
}
public void setVariant(String variant) {
this.variant = variant;
}
public String getQuantity() {
return quantity;
}
public void setQuantity(String quantity) {
this.quantity = quantity;
}
public static void main(String[] args) {
// HashSet<Variant> set = new HashSet<>();
// LinkedHashSet<Variant> linkedSet = new LinkedHashSet<>(); // stores
// in input order
/*
* You can use treeset to store data in custom order, in this case
* lexicographically
*/
TreeSet<Variant> treeSet = new TreeSet<>(new VariantComparator());
}
}
I have a program that I have to use a HashSet for. My question arises from the fact that HashSets mainly contain one object, but if I wish to send information to the other class, it takes three objects: one string, one int, and one boolean.
The assignment says that I must use a HashSet
Constructor I am trying to send information to:
public Magic (String name, int size, boolean isVisible)
I have a class that is supposed to be sending sets of spells containing name, size, and isVisible.
Magic.go() class:
public void go()
{
int i = 0;
while (i < size) {
if (isVisible == true) {
System.out.println(name + "!");
}
i++;
}
}
Just create an object which contains all the three fields like this:
import java.util.Objects;
public class NameSizeVisible {
private final String name;
private final int size;
private final boolean isVisible;
public NameSizeVisible(String name, int size, boolean isVisible) {
this.name = name;
this.size = size;
this.isVisible = isVisible;
}
public String getName() {
return name;
}
public int getSize() {
return size;
}
public boolean isVisible() {
return isVisible;
}
#Override
public int hashCode() {
return Objects.hash(name,size,isVisible);
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NameSizeVisible other = (NameSizeVisible) obj;
if (isVisible != other.isVisible)
return false;
if (!Objects.equals(name, other.name))
return false;
if (size != other.size)
return false;
return true;
}
}
You can use a HashSet that stores Objects. So you would have:
HashSet<Object> set = new HashSet<>();
set.add(name);
set.add(size);
set.add(isVisible);
Then when you access the objects you just need to cast them to their respective types:
String name = "";
int size = 0;
boolean isVisible = false;
for (Object o : set) {
if (o instanceof String) {
name = (String) o;
} else if (o instanceof int) {
size = (int) o;
} else {
isVisible = (boolean) o;
}
}
I want to sort a LinkedHashMap based on object attribute and using Comparable. Here is my code:
public class MapClass{
public static void main(String args[]){
sortMapBasedOnValueObjectUsingComprable();
}
public static void sortMapBasedOnValueObjectUsingComprable(){
Map map = new LinkedHashMap();
map.put("2",new Pojo("456"));
map.put("4",new Pojo("366"));
map.put("1",new Pojo("466"));
map.put("8",new Pojo("5666"));
map.put("9",new Pojo("456"));
map.put("3",new Pojo("66"));
// How to sort ...?
Set<Map.Entry<String,Object>> st = map.entrySet();
Iterator itr = st.iterator();
while(itr.hasNext()){
Map.Entry mxt= (Map.Entry)itr.next();
Pojo pj = (Pojo)mxt.getValue();
System.out.println(pj.getX());
}
}
public class Pojo implements Serializable, Comparable<Object>{
private static final long serialVersionUID = 1L;
private String x;
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
public Pojo(String x) {
super();
this.x = x;
}
#Override
public int compareTo(Object o) {
return 0;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((x == null) ? 0 : x.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pojo other = (Pojo) obj;
if (x == null) {
if (other.x != null)
return false;
} else if (!x.equals(other.x))
return false;
return true;
}
}
So u need to first dump your entrySet into a List and then sort it.You can't sort a set unless you are using a TreeSet.I will prefer to dump it into a List which implements RandomAccess so that I can fetch any element by its index.
Map<String,Object> map = new LinkedHashMap<>();
Set<Map.Entry<String,Object>> st = map.entrySet();
List<Map.Entry<String,Object>> listSort = new ArrayList<>(st);
Collections.sort(listSort,new Comparator<Map.Entry<String,Object>(){
public int compare(Map.Entry<String,Object> entry1,Map.Entry<String,Object> entry2){
return ((Comparable)entry1.getValue).compareTo(entry2.getValue.compareTo);
});
Just iterate the list and you can get the elements sorted
Note:- I have implemented a Comparator using anonymous inner class and this Comparator in turn uses the Comparable instance of Pojo class