Add identical objects to a Set<E> - java

How do I make my code to add identical objects to a SET? I guess I will have to do something with hashcode() or equal() functions.
Class Order {
private id;
private Set<Discount>;
}
Class Discount {
private id;
private Long amount;
}
Now if I try to save two discounts of $1 each, the SET only shows one discount. When hibernate saves it, discounts will have different IDs, but they are same as of now. Don;t want to change the definition of Order class, as it's a big project and changes will be endless

According to the JavaDoc for the Set interface, a set is not allowed to contain duplicate identical elements (as defined by equals and hashcode). While this will work fine when hibernate saves the discounts (since you said the ids will be different), the ids are the same right now, so what you are trying to accomplish is not possible without doing things that future people who will be stuck maintaining your code will hate you for.
Since you do not desire to change the Order class, your best recourse is to retroactively change the ids on your discounts to be unique.

You cannot add identical objects to a set, because that is the point of a set. A set contains unique elements. You would be better off using a list or a map.

Related

Java collection : criteria based traversing or another view to a collection

Is there any way or if any java library available which can let me traverse through selected list items only(not all) which satisfies the condition?
For example: I have a list of employee, and I want to traverse the list of employees who are manager only. I don't want to put a condition or filter but want to traverse the list of manager only.
For this, I can define the criteria while creating the list. So every time, when I'll add an item to the list a pointer to a list item, which satisfies the criteria, will be saved in another list.
It's like providing another view to original list.
Although it can be done using filter, but I would have to basically access each list item, compare and then process.
It can have memory overhead as it'll maintain extra list for each criteria, but I believe it'll reduce processing time.
I am expecting that my list would not contain more than 30 items on average.
Update
After some brainstorming, I have come up with below solution.
View<T>
List<T>
boolean checkCondition(T);
boolean updateView(T);
managerView
boolean checkCondition(T){
return token.getDesignation == designation.MANAGER;
}
salaryView
boolean checkCondition(T){
:
}
ViewableList<T> list
list.addView(managerView)
list.addView(salaryView)
ViewableList<T>
List<View<T>> views;
add(T){
originalList.add(T);
foreach views{
if(view.checkCondition(T)){
view.add(T);
}
}
}
addView(View){
views.add(view)
}
I can achieve Insert, Search, and Delete operation easily. But I am still finding difficulty to update the view when the field of view of an object is updated.
Possible solutions
I annotate list item's field; Write an aspect. So whenever the value of annotated field is changed, it can call updateView() of corresponding view.
Employee{
#View(type=DesignationView.class)
Designation designation;
}
But there is a chance that a field is used in constructing multiple views. So I would have to pass list of view classes in #View annotation, which looks pretty odd. Moreover, I want to avoid use of reflection and aspect due to performance. Otherwise there'll not be any sense to put all this effort.
Please lemme know if you have an idea how I can implement it.
Wouldn't it be better if you use Map. In this map, key could be category and value will be list. So when traversing only get the entry for that key.
And how do you expect such a thing to be coded in such a way as to be so generic that it's useful as a general purpose library rather than specific to your very narrow requirements?
Which would be the only kind of implementation that it is a sensible idea to release as a standalone library of course.
So no, something like that isn't going to exist. You're going to have to create some of your own code.

Fastest way to sort a set

I'm replacing an application used at work, using Hibernate with an existing database. I can't modify the database since it's in use with other processes. When Hibernate pulls the main object from the db, the child objects are put in an unordered set. I've never really dealt with sets or sorting sets much before.
I need to display the last (chronologically) child for each set. There are no dates stored for the child objects, but since the id field in the db is AUTO_INCREMENT, I can sort them by id in lieu of a date.
One of the complaints about the existing system in use is that it's really, really slow. I'd like to show a definite increase of speed with the new application.
Given a Person object (variable name "off") with 0 to n "home addresses", I'm using:
Set addressSet = off.getAddresses();
List<Address> addressList = new ArrayList<>();
Iterator i = addressSet.iterator();
while(i.hasNext()){
addressList.add((Address) i.next());
}
Collections.sort(addressList, new AddressComparator());
Address a = null;
if(addressList.size()>0){
a = addressList.get(addressList.size()-1);
}else{
a = new Address(); //creates new Address object with empty strings
//for fields
}
My simple comparator is:
public int compare(Address t, Address t1) {
return t.getId().compareTo(t1.getId());
}
My question: Through either Java or Hibernate, is there a faster method to sort the sets?
From my point of view, you don't need to sort at all. Use
Collections.max()
or
Collections.min()
with your custom comparator provided to find the address you want. This has O(n) run time in worst case compared to O(nlog(n)) sorting time since you do not sort and only iterate your set once. The positive part also is that you don't need to convert your Set to List as the max and min methods work with any Collection instance.
Another advantage (at least for me) is that Collections utilities are part of the java runtime, so you don't need to add any third-party libraries.
I'm not sure if there are multiple sets, but from the code it seems like you are just getting the Address with the highest id. This can be achieved with the following sql, which wouldn't require sorting.
select * from table where id = (select max(id) from table);
You can do this without temporary List.
TreeSet sortedSet = Sets.newTreeSet(new AddressComparator());
sortedSet.addAll(off.getAddresses());
return sortedSet.first(); // or sortedSet.last() see what is suitable for you
Details on Sets.
UPD.
Please also see solution with Guava Ordering. It will allow you to get max element without temporary collection at all.
Ordering<Adress> ordering = Ordering.from(new AddressComparator());
return ordering.max(off.getAddresses());
You can sort at the database level in JPA/Hibernate by using the #OrderBy property where the sort is on a non-nested property. So in your case you can do this.
e.g.
#OneToMany
#OrderBy("id");
public Set<Address> addresses;
and Hibernate will ensure the collection is in a sorted set.
If the sort field happened to be on a nested property (which it isn't in your case) e.g. person.address.town.population then you can still have Hibernate deal with sort using the Hibernate specific (non-JPA) #Sort annotation which will ensure a sorted set as above but will sort using an in memory sort rather than a DB order by clause.
#OneToMany
#Sort(//natural or specify a comparator);
public Set<Address> addresses;
That does not get you the most recent address of course. If you don't want to change the mapping from Set to List which would allow you get the latest based on index, then you could also do this in the Database tier by various means e.g. by creating a view based on max address id for each person.
#Entity
#Table(name = "vw_most_recent_addresses"
public class MostRecentAddress extends Address{
}
public class Person{
#OneToMany
#OrderBy("id");
public Set<Address> addresses;
#OneToOne
public MostRecentAddress mostRecentAddress;
}

4 Key Value HashMap? Array? Best Approach?

I've got loads of the following to implement.
validateParameter(field_name, field_type, field_validationMessage, visibleBoolean);
Instead of having 50-60 of these in a row, is there some form of nested hashmap/4d array I can use to build it up and loop through them?
Whats the best approach for doing something like that?
Thanks!
EDIT: Was 4 items.
What you could do is create a new Class that holds three values. (The type, the boolean, and name, or the fourth value (you didn't list it)). Then, when creating the HashMap, all you have to do is call the method to get your three values. It may seem like more work, but all you would have to do is create a simple loop to go through all of the values you need. Since I don't know exactly what it is that you're trying to do, all I can do is provide an example of what I'm trying to do. Hope it applies to your problem.
Anyways, creating the Class to hold the three(or four) values you need.
For example,
Class Fields{
String field_name;
Integer field_type;
Boolean validationMessageVisible;
Fields(String name, Integer type, Boolean mv) {
// this.field_name = name;
this.field_type = type;
this.validationMessageVisible = mv;
}
Then put them in a HashMap somewhat like this:
HashMap map = new HashMap<String, Triple>();
map.put(LOCAL STRING FOR NAME OF FIELD, new Field(new Integer(YOUR INTEGER),new Boolean(YOUR BOOLEAN)));
NOTE: This is only going to work as long as these three or four values can all be stored together. For example if you need all of the values to be stored separately for whatever reason it may be, then this won't work. Only if they can be grouped together without it affecting the function of the program, that this will work.
This was a quick brainstorm. Not sure if it will work, but think along these lines and I believe it should work out for you.
You may have to make a few edits, but this should get you in the right direction
P.S. Sorry for it being so wordy, just tried to get as many details out as possible.
The other answer is close but you don't need a key in this case.
Just define a class to contain your three fields. Create a List or array of that class. Loop over the list or array calling the method for each combination.
The approach I'd use is to create a POJO (or some POJOs) to store the values as attributes and validate attribute by attribute.
Since many times you're going to have the same validation per attribute type (e.g. dates and numbers can be validated by range, strings can be validated to ensure they´re not null or empty, etc), you could just iterate on these attributes using reflection (or even better, using annotations).
If you need to validate on the POJO level, you can still reuse these attribute-level validators via composition, while you add more specific validations are you´re going up in the abstraction level (going up means basic attributes -> pojos -> pojos that contain other pojos -> etc).
Passing several basic types as parameters of the same method is not good because the parameters themselves don't tell much and you can easily exchange two parameters of the same type by accident in the method call.

What would be better set, array or list?

I need to make a list of people and their time of arrival to a party, and when ever they leave I need to take them off this list. (the party maximum is 150)
Set would provide me that in no case I would add the same person twice.
List would provide me flexibility to start the list with few spaces (in case no one shows up).
Arrays (not sure what they provide) but I used them more often.
My idea was either to create 2 arrays one with names and what with times. When someone comes in, I save name in one and time on the other. When he/she leaves I search for his/her name, delete it and use the same index to delete the time on the other array.
A list could have one array of 2 elements, and then I will only need to add it in one location but searching would be a TINY more complicated.
Or maybe I am complicating this too much?
Map implementation:
public final class Person
{
... remainder left to the student ...
}
Map<Person, Date> currentPartyAttendees; // date is arrival time.
Set implementation:
public final class PartyAttendee
{
... person details ...
Date arrive;
int hashcode()
{
... use Apache HashCodeBuilder ...
}
boolean equals(Object other)
{
... implementation left to student. Use Apache EqualsBuilder ...
}
}
Set<PartyAttendee> currentPartyAttendees;
Using a HasMap would suit your purpose, as you can use the person's name as a key to add and retrieve the entry for the person, and it offers constant time performance, so regardless of how large the set grows, the performance should remain consistent.
The way you've described your use-case, why not consider the HashMap, or some other Map based implementation?
Unless of course, there's a binding for you to use a List [or similar] based data structure.
Just use a List<> and a Data structure the represents guest.
Subclass List to mark the arrival and departure time and add/remove methods. You can also use set, but then you'll have to generate a hashCode and equals method. I'm not sure you want to do that, cause people may have the same names (unless you have other data like SSN, bday, middle name etc)
public Class Guest{
private String firstName, lastName;
private long arrivalTime, departureTime;
....
}
public class MyGuests extends ArrayList<Guest>{
#Overide
public void add(Guest g){
//record arrival time here
super.add(g)
}
#Overide
public void remove(Guest g){
//record departure time here
super.remove(g);
}
}
I think you can use arrays as well, and, instead two arrays, use an arrays of 'Person' model, that holds the name of the person, arrive time and leave time. Before you insert on array, you can verify if the list already contains this person.
ps: don't forget to overwrite equals() and hashCode() in your model
LinkedHashMap - a container of key-value pairs that maintains the order of their insertion. The key would be the person (a simple String or a designated class), the value would be the time of arrival, e.g. a Date.

How to implement n:m relation in Java?

I need to implement an n:m relation in Java.
The use case is a catalog.
a product can be in multiple categories
a category can hold multiple products
My current solution is to have a mapping class that has two hashmaps.
The key of the first hashmap is the product id and the value is a list of category ids
The key to the second hashmap is the category id and the value is a list of product ids
This is totally redundant an I need a setting class that always takes care that the data is stored/deleted in both hashmaps.
But this is the only way I found to make the following performant in O(1):
what products holds a category?
what categories is a product in?
I want to avoid full array scans or something like that in every way.
But there must be another, more elegant solution where I don't need to index the data twice.
Please en-light me. I have only plain Java, no database or SQLite or something available. I also don't really want to implement a btree structure if possible.
If you associate Categories with Products via a member collection, and vica versa, then you can accomplish the same thing:
public class Product {
private Set<Category> categories = new HashSet<Category>();
//implement hashCode and equals, potentially by id for extra performance
}
public class Category {
private Set<Product> contents = new HashSet<Product>();
//implement hashCode and equals, potentially by id for extra performance
}
The only difficult part is populating such a structure, where some intermediate maps might be needed.
But the approach of using auxiliary hashmaps/trees for indexing is not a bad one. After all, most indices placed on databases for example are auxiliary data structures: they coexist with the table of rows; the rows aren't necessarily organized in the structure of the index itself.
Using an external structure like this empowers you to keep optimizations and data separate from each other; that's not a bad thing. Especially if tomorrow you want to add O(1) look-ups for Products given a Vendor, e.g.
Edit: By the way, it looks like what you want is an implementation of a Multimap optimized to do reverse lookups in O(1) as well. I don't think Guava has something to do that, but you could implement the Multimap interface so at least you don't have to deal with maintaining the HashMaps separately. Actually it's more like a BiMap that is also a Multimap which is contradictory given their definitions. I agree with MStodd that you probably want to roll your own layer of abstraction to encapsulate the two maps.
Your solution is perfectly good. Remember that putting an object into a HashMap doesn't make a copy of the Object, it just stores a reference to it, so the cost in time and memory is quite small.
I would go with your first solution. Have a layer of abstraction around two hashmaps. If you're worried about concurrency, implement appropriate locking for CRUD.
If you're able to use an immutable data structure, Guava's ImmutableMultimap offers an inverse() method, which enables you to get a collection of keys by value.

Categories

Resources