Java: HashSet multiple types - java

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

Related

HashMap key generation based on hashing

My intention was to make a caching service for a database results, that I can paginate differently based on client's requests.
So, upon the (search) request I am making a key that is composed of parameters, which are in form of two Map<String, String[]> and a:
public class DocMaintainer {
public Manipulator creator;
public Manipulator lastChange;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DocMaintainer that = (DocMaintainer) o;
return Objects.equals(creator, that.creator) &&
Objects.equals(lastChange, that.lastChange);
}
#Override
public int hashCode() {
return Objects.hash(creator, lastChange);
}
}
public class Manipulator {
public Date fromDate;
public Date toDate;
public String userId;
public String system;
public Manipulator() {
this.userId = "";
this.system = "";
this._fromJoda = new DateTime(Long.MIN_VALUE);
this._toJoda = new DateTime(Long.MAX_VALUE - DateTimeConstants.MILLIS_PER_WEEK);
}
private DateTime _fromJoda;
private DateTime _toJoda;
public DateTime get_fromJoda() {
_fromJoda = fromDate != null ? new DateTime(fromDate) : _fromJoda;
return _fromJoda;
}
public DateTime get_toJoda() {
_toJoda = toDate != null ? new DateTime(toDate) : _toJoda;
try {
_toJoda = _toJoda.plusDays(1);
} catch (Exception e) {
System.out.println(e);
}
return _toJoda;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Manipulator that = (Manipulator) o;
return Objects.equals(fromDate, that.fromDate) &&
Objects.equals(toDate, that.toDate) &&
Objects.equals(userId, that.userId) &&
Objects.equals(system, that.system);
}
#Override
public int hashCode() {
return Objects.hash(fromDate, toDate, userId, system);
}
}
As you can see I intended to use hashing to create a "key":
public class SearchKey {
public int conjunctionHash;
public int disjunctionHash;
public int maintainerHash;
public SearchKey(int conjunctionHash, int disjunctionHash, int maintainerHash) {
this.conjunctionHash = conjunctionHash;
this.disjunctionHash = disjunctionHash;
this.maintainerHash = maintainerHash;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SearchKey searchKey = (SearchKey) o;
return conjunctionHash == searchKey.conjunctionHash &&
disjunctionHash == searchKey.disjunctionHash &&
maintainerHash == searchKey.maintainerHash;
}
#Override
public int hashCode() {
return Objects.hash(conjunctionHash, disjunctionHash, maintainerHash);
}
}
a key-object is used directly as a caching key in a singleton service:
#Named
#Singleton
public class SearchCacheSrv {
private Map<SearchKey, ValidMainteinersList<FindDTO>> cache = new HashMap<>();
public ValidMainteinersList<FindDTO> getCached(SearchKey searchKey) {
if (cache.containsKey(searchKey))
return cache.get(searchKey);
else
return new ValidMainteinersList<FindDTO>();
}
public SearchKey makeAkey(Map<String, String[]> conjunction,
Map<String, String[]> disjunction,
DocMaintainer maintainer) {
return new SearchKey(conjunction.hashCode(), disjunction.hashCode(), maintainer.hashCode());
}
public ValidMainteinersList<FindDTO> cache(SearchKey searchKey, ValidMainteinersList<FindDTO> findDTOS) {
return cache.put(searchKey, findDTOS);
}
public void clearCache() {
cache.clear();
}
}
Unfortunately this is not behaving the way I expected and I'm getting different hashes/keys generated for the same parameters.
Naturally question is why?
The problem here is that the hashCode of an array does not depend on the contents, but on the reference. That means that if you have two conjunction / disjunction keys that are equal, but the contained arrays are not the same objects, then the hashcode of the keys will be different.
The solution that probably takes the least effort is replacing the arrays with ArrayLists, which do base their hashCode on the content.
I actually don't see the point of passing conjunction.hashCode(), ... to your SearchKey constructor; I never had to do it this way, but it could be my mistake.
Try passing actual values to your SearchKey class, not hashCodes, so the hashCode method always returns a consistent value.

How I can remove and update sorted elements in TreeSet?

I have some entity class
class Data{
private String quoteID;
private String bidOrOffer;
private float price;
private long volume;
private Date createDate;
public Data(String quoteID, String bidOrOffer, float price, long volume) {
this.quoteID = quoteID;
this.bidOrOffer = bidOrOffer;
this.price = price;
this.volume = volume;
createDate = new Date();
}
#Override
public int hashCode() {
int hash = 5;
hash = 13 * hash + Objects.hashCode(this.quoteID);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Data other = (Data) obj;
if (!Objects.equals(this.quoteID, other.quoteID)) {
return false;
}
return true;
}
}
and I push some elements into TreeSet whit special order
Comparator<Data> offerOrder = (Data o1, Data o2) -> {
if(o1.equals(o2))
return 0;
if(o1.getPrice() == o2.getPrice()
&& o1.getVolume() == o2.getVolume()){
return o1.getCreateDate().after(o2.getCreateDate())? 1:-1;
}
if(o1.getPrice() == o2.getPrice()){
return o1.getVolume() > o2.getVolume()? 1:-1;
}
if(o1.getPrice() > o2.getPrice())
return 1;
else
return -1;
};
Set<Data> treeSet = new TreeSet<>(offerOrder);
treeSet.add(new Data("Q1", "OFFER", 1.32f, 1000000));
treeSet.add(new Data("Q6", "OFFER", 1.32f, 1000000));
treeSet.add(new Data("Q7", "OFFER", 1.33f, 200000));
The main goal of this task it is remove and update some data by quoteID
but if I do this
treeSet.contains(new Data("Q7", "OFFER", 0, 0)); //return false
thereafter method remove doesn't work too.
Any ideas?
While inserting "Q7" the comparator returns 1 in compare to "Q1".
If you now want to remove "Q7" with new Data("Q7", "OFFER", 0, 0) the comparator returns -1.
So the child of the "wrong" path of the tree compared next.
treeSet.contains(new Data("Q7", "OFFER", 2, 0)) would return true (compare to "Q1" returns 1).
You should take care of change the implementation of your Comparator<Data> offerOrder because that implementation does not permit to find the object you're looking for with treeSet.contains.
For example in your case:
Comparator<Data> offerOrder = (Data o1, Data o2) -> {
return o1.quoteID.compareTo(o2.quoteID);
};
And then returns true:
treeSet.contains(new Data("Q7", "OFFER", 0, 0)); //return true
There is also an error in your equals method:
final Quote other = (Quote) obj;
if (!Objects.equals(this.quoteID, other.quoteID)) {
return false;
}
You should use:
if (!this.quoteID.equals(other.quoteID)) {
return false;
}
And given that quoteID is a String is not clear what is the Quote class.
I suggest to change use hashCode and equals methods in this way:
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((quoteID == null) ? 0 : quoteID.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;
Data other = (Data) obj;
if (quoteID == null) {
if (other.quoteID != null)
return false;
} else if (!quoteID.equals(other.quoteID))
return false;
return true;
}
You cannot search "quoteID" as is inside Data object. You have to iterate each Data object and match for "quoteID".
Iterator<Data> iterator = treeSet.iterator();
while(iterator.hasNext()){
Data dataobj = iterator.next();
String qID = dataobj.quoteID;
if(qID.equals("Q7")){
//write your code.
}
}

how can i print custom class Duplicate if i am adding that object in list?

How can i print the duplicate of custom class object if i am adding that object inside list.
class Bank{
int id;
String name;
public Bank(int id,String name){
this.id=id;
this.name=name;
}
#Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
return super.equals(obj);
}
#Override
public String toString() {
return id+"\t"+name;
}
}
public class Service {
public static void main(String[] args) {
List<Bank> al=new ArrayList<Bank>();
Bank a=new Bank(11,"employee");
Bank b=new Bank(11,"employee");
Bank c=new Bank(12,"Bank");
Bank d=new Bank(12,"Bank");
al.add(a);
al.add(b);
al.add(c);
al.add(d);
}}
Here four bank object i am adding inside list. But a,b pointing to same object and similarly c and d pointing to same object How can i pointing to duplicate from above List.
You have 2 options to achieve this...
1st one is out of the box:
you need to use a Set, this collection doesnt allow duplicates, but you has no insertion order
2nd option.
you can write a method that is checking in the list is the element you are trying to insert is already there... list.contains(bank); where bank is the mthod to check...
in both cases is necessary to override the methods hashcode and equals(you already have this) in the class bank.
Example:
static List<Bank> al;
public static void main(String[] args) {
al = new ArrayList<Bank>();
Bank a = new Bank(11, "employee");
Bank b = new Bank(11, "employee");
Bank c = new Bank(12, "Bank");
Bank d = new Bank(12, "Bank");
addIfNotinList(a);
addIfNotinList(b);
addIfNotinList(c);
addIfNotinList(d);
System.out.println(al);
}
private static void addIfNotinList(Bank bank) {
if (!al.contains(bank)) {
al.add(bank);
}
}
and the Bank class
public class Bank {
int id;
String name;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.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;
Bank other = (Bank) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public Bank(int id, String name) {
this.id = id;
this.name = name;
}
#Override
public String toString() {
return "Bank [id=" + id + ", name=" + name + "]";
}
}
Implement equals according to:
public boolean equals( Object obj ){
if ( this == obj ) return true;
if ( !(obj instanceof Bank) ) return false;
Bank other = (Bank)obj;
return this.id == other.id && this.name == other.name;
}
Perhaps comparing the id alone would be sufficient to establish equality.
Now you can do:
List<Bank> al=new ArrayList<Bank>();
Bank a=new Bank(11,"employee");
al.add( a );
Bank b=new Bank(11,"employee");
if( al.contains( b ) ){
// duplicate
} else {
al.add( b );
}

Check ArrayList for duplicates

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

Method that adds elements to set always throwing custom exception

Ok, so I've got a method which adds elements to a list but it is always throwing my custom exception, no matter what, even when there are no elements in the Set I made.
private Set<Plan> planSet = new HashSet<Plan>();
public Plan createPlan(String name) throws DuplicatePlan{
Plan plan = new Plan(name);
if(!planSet.contains(plan)){
planSet.add(plan);
} else {
throw(new DuplicatePlan("Error, duplicate plan"));
}
return plan;
}
I'm thinking that my equals() and hashCode() methods are causing this. Currently I'm using the default overridden Eclipse hashCode() and equals(), this is what I've got there:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.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;
}
Plan other = (Plan) obj;
if (name == null) {
if (other.name != null){
return false;
}
} else if (!name.equals(other.name)){
return false;
}
return true;
}
This is what Plan does:
private String name;
private Set<Tables> tablesSet;
public Plan(String name){
this.name = name ;
}
Here's what's supposed to happen if a user sets the same name in the TextField:
newPlan.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent action){
if(!newPlan.getText().isEmpty()){
try {
String name = planName.getText();
plan.createPLan(name);
esquema = esquemas.createPlan(planName.getText());
optionsPlans.getItems().add(plan.getName());
} catch (DuplicatePlan e) {
dialog.errorDialog(planError, duplicate);
}
} else {
dialog.errorDialog(empty, emptySpace);
}
}
});
Had to use Answer because it was too long for comment.
This here looks suspicious to me:
String name = planName.getText();
plan.createPLan(name);
esquema = esquemas.createPlan(planName.getText());
I.e. what's up with createPLan and createPlan? Copy & paste error? Or are you calling the same method twice (which would explain the behavior)?

Categories

Resources