LinkedHashSet remove duplicates object
Solution 1
All Set
implementations remove duplicates, and the LinkedHashSet
is no exception.
The definition of duplicate is two objects that are equal to each other, according to their equals()
method. If you haven't overridden equals
on your Product
class, then only identical references will be considered equal - not different instances with the same values.
So you need to add a more specific implementation of equals
(and hashcode
) for your class. For some examples and guidance, see Overriding equals and hashcode in Java. (Note that you must override hashcode
as well, otherwise your class will not behave correctly in hash sets.)
Solution 2
I won't give you straight answer, but a couple of advices.
- If you want to put
Product
in aSet
you need to implement itsequals()
andhashCode()
methods. - When implementing
equals()
you will have to decide what "equality" for aProduct
means, (Set
can contain only one instance in terms on "equality"). For instance, if twoProduct
instances are "equal" is it enough if they have the same ID or should we also take quantity into account?. It's not easy to answer this question in your case, but please read on. - Normally in situation like this only ID is taken into account. In that case you shouldn't have two
Product
instances in memory with differentquantities
, because one of them would represent a state that is incorrect (ie. particular product's quantity can be either 1 or 3, not both at a time). -
I think the design is not fully correct.
Product
class in your case represents a general product description (including price), soquantity
doesn't really fit there. If someone can order a couple of copies ofProduct
I think you should create another class such asOrder
orOrderLine
which specifies what product is ordered and the corresponding quantity, eg:class OrderLine { private Product product; private Integer quantity; }
With design like this it's easy to answer question from point 2.
Product.equals()
should compare the ID only, andOrderLine.equals()
both the product (ID) and quantity.
Solution 3
I would suggest you implement your own hash function in a way that it hashes elements with equal ID-s with the same code. This will solve your issue, without you having to code it explicitly.
insict
Updated on June 11, 2022Comments
-
insict almost 2 years
I have simple question to you, I have class Product that have fields like this:
private Integer id; private String category; private String symbol; private String desc; private Double price; private Integer quantity;
I want to remove duplicates item from LinkedHasSet based on ID, e.g Products that have same ID but diffrent quantity will be add to set, I want to remove (update) products with same ID, and it will by my unique id of object, how to do that?
e.g Product: id=1, category=CCTV, symbol=TVC-DS, desc=Simple Camera, price=100.00, quantity=1 Product: id=1, category=CCTV, symbol=TVC-DS, desc=Simple Camera, price=100.00, quantity=3
won't be added to set
my code:
public void setList(Set<Product> list) { if(list.isEmpty()) this.list = list; else { this.list.addAll(list); Iterator<Product> it = this.list.iterator(); for(Product p : list) { while(it.hasNext()) { if(it.next().getId() != p.getId()) it.remove(); this.list.add(p); } } } }
-
insict about 11 yearsI have equal and hashCode methods generated by eclipse, so I must use Obj.equal(Obj) style ?
-
Andrzej Doyle about 11 yearsNo, the LinkedHashSet will call
equals
itself internally, and will not insert an element that is equal to one already in the set. If you're seeing "duplicates" in your set, then the equals method must not be defined how you expect - you must have two duplicatesa
andb
such thata.equals(b)
returns false. (Or, since it's a hash-based set,a.hashCode() != b.hashCode()
) -
Punith Raj about 11 yearsYou can retain the default overridden hashcode implementation from eclipse, your Product class should have the logic of returning false when the productId is equal when compared with another object, and all other properties can be left unchecked for equality... Dont forget to handle transitive, reflexive and symmetric equlality for objects
-
insict about 11 yearsbut how to do that when in equals method signature I must have Object type, and compiler don't know that it will be Product. I can not use generic in method signature because it won't be overridden
-
Andrzej Doyle about 11 years@user1853125 That's how the method is defined, because you can compare equality against any object. Typically, implementations will check whether the other object is the same class - if not, they immediately return
false
, otherwise they cast toProduct
and go on to compare fields. If you have a look at start of the Eclipse-generated code, it's almost certainly doing something like this. You just need to change the logic that compares fields. -
insict about 11 yearsok, I wrote something like this:
@Override public boolean equals(Object obj) { if(!(obj instanceof Product)) return false; Product p = (Product) obj; if(this.id.hashCode() == p.id.hashCode() ) { return true; } else { return false; } }
and its works properly -
insict about 11 yearsstrange, equals works, but LinkedHashSet still adds same-id objects ;/
-
Adam Dyga about 11 years@user1853125 Your
equals()
method is implemented wrong. You should compare object's fields, not thehashCode()
result. There is a chance that completely different objects return the same hash code. You should first learn how hashtables work and why it is important to implementequals()
andhashCode()
properly. Irrespective of that, even if you implementequals()
properly, you've got design issues in the code, which will cause other problems later -
insict about 11 yearsso I must create
Order
class with simple setter and getter methods and adds overriden hashCode and equals methods? -
insict about 11 yearsI use Product class with quantity because I use it in Datatable component with selector column, so it quite difficult to implement it by using two class.
-
Adam Dyga about 11 years@user1853125 I don't fully understand what "Datatable component with selector column" is, but if you have just single table which contains both the product description, price and quantity, then the DB design is also wrong and it's probably the root of your problems. You should have one table for Product (and its descriptions) and another one for Orders (that has a foreign key to Product, and a quantity column). The Order usually has its own ID too.
-
insict about 11 yearsbut when I have OrderLine class i must to create new
equals
andhashCode
methods to define unique ID, that's really complicated