How do I compare two lists? - java

CompareList removedList = new CompareList();
CompareList addedList = new CompareList();
This is how I'm adding elements inside
addedList.add(new Objec("Var_a", "1"));
and class Objec has two strings.
How can I compare that? I can't use contains like I could with ArrayList of Strings?
In CompareList I have
public boolean equals(CompareList l) {
if (l.containsAll(this)) {
if (this.containsAll(l)) {
return true;
}
}
return false;
}
and in Objec
public Objec(String n, String s) {
this.name=n;
this.surname=s;
}
public String toString() {
return " Name: " + name + ", Surname: " + surname;
}
I see that many people are confused with my question. So what I want?
List 1:
Samy Joe
Emma Than
Julia Rob
List 2:
Samy Joe
Emma Than
Anna Sky
Removed Julia Rob and added Anna Sky. But I don't know how to do it when my lists contains of object that have two strings?

This piece of code compares if the lists are equal, that is, contains the same elements.
static boolean same(Collection<?> a, Collection<?> b) {
if (a.size() != b.size()) {
return false;
}
List<?> c = new ArrayList<>(a);
c.removeAll(b);
return c.isEmpty();
}
If the sizes are not equal, then the lists are never equal.
Else, if the sizes are equal, then we know that both lists contain one or more elements that are not present in the other list. So we make a new list from one of the lists (list a in my case), and then we remove the elements of b.
You don't need to use your own class CompareList, instead you could just use an ArrayList or something.
In order to compare your Objec to another one, you'll need to implement equals(Object) and hashCode() correctly.
If you want to know which elements are not contained in the other list, then you can use this:
static HashMap<Collection<?>, Collection<?>> disjoints(Collection<?> a, Collection<?> b) {
List<?> aa = new ArrayList<>(a);
aa.removeAll(b);
List<?> bb = new ArrayList<>(b);
bb.removeAll(a);
HashMap<Collection<?>, Collection<?>> map = new HashMap<>();
map.put(a, aa);
map.put(b, bb);
return map;
}
It returns a map with as keys the two collections and as values the elements of the collection specified by the key, which are not contained in the other collection. For example, if you want to know the elements of a not present in b, then call disjoints(a, b).get(a).
Note: I call the lists collections, because they are. In Java, a List is a subtype of Collection.

You need to override the equals method in your custom object like this:
public class MyObject {
private String name;
private String surname;
#Override
public boolean equals(MyObject myObject) {
// assert that name and surename can not be null or check for this
if (!this.name.equals(myObject.name)) {
return false;
}
if (!this.surname.equals(myObject.surname)) {
return false;
}
return true;
}
}
The contains-Method of a list will be use the equals method to check the equality of your objects.
But the link that #Prakash has posted is the better way do do that. I think no one understand what your attention is to do with yout CompareList and why you use a custom one ;)
EDIT:
Sorry, had mistake in the Signature.
#Override
public boolean equals(Object obj) {
if (!(obj instanceof MyObject) {
return false;
}
// else cast and use code above
}

You're question: "How can I compare that?"
The first thing to keep in mind is that you can compare in 2 ways.
so think about that first.
Equality:
When comparing for equality
use equals() and while you're at it implement hashCode().
Comparing / sorting:
When are 2 objects considered lower then, same, or higher then the other?
implement "Comparable" interface and override compareTo.
You're post contains the equals() so lets say that is what you want to do.
If you want to use containsAll(), keep in mind that it uses equals from the class the list contains to figure out to return true/false. So you should probably:
add equals() to your "Objec" class.

Related

Remove Element in ArrayList in loop

I need help. I tried to remove an element from an ArrayList.
I have two lists. One list from a file, the second list from the database.
I need to find the same elements to later remove them from the original list, and thus have a list with differences.
List<BinInternacionalMarcaDEL> listDiff = new ArrayList<BinInternacionalMarcaDEL>();
ListOriginal= binInternacionalRepositoryDEL.findAllByBin();
public List<BinInternacionalMarcaDEL> Differences(List<BinInternacionalMarcaDEL> listA,
List<BinInternacionalMarcaDEL> listB) {
try {
for(BinInternacionalMarcaDEL elementA: listaA){
for(BinInternacionalMarcaDEL elementB: listaB) {
if(elementA.getNumRangoini().compareTo(elementB.getNumRangoini()) == 0 ){
listDiff.add(elementA);
}
}
}
ListOriginal.removeAll(listDiff);
} catch (Exception e) {
LOGGER.error(e.toString());
}
but this doesn't work.
just you can do one thing
listA.retainAll(listB);
here now listA contains only similar elements in both ListA and ListB.
Example:
List<String> listA = new ArrayList<>(Arrays.asList("12","13","15","2","5")) ;
List<String> listB = new ArrayList<> (Arrays.asList("2","12","48","49","55"));
listA .retainAll(listB );
System.out.println(listA ); //[12, 2]
Java list remove and contains methods are implemented using equality of objects. This logic is implemented in hashCode and equal method in your class and all classes in Java inherit this attribute from the Object class.(to be honest ArrayList doesn't use hashCode in implementing remove and contains metheds but in java contract you should implement these two methods together). here when you are adding element to listDiff you are defining your own equality which is based on equality of attribute numRangoini(using compateTo method) and when you request the list class to remove them from list(with removeAll method). removeAll remove them based on the equality of that two object. Since you haven't defined this logic in your own class.
this behaviour is inherited from object class which is based on strict equality. by default two object are equal if they reference the same object.
Solution: define the logic for equality in your own class in equal method. This method should return true if two object has the same attribute value numRangoini. don't forget to define hashCode as well. and here is the rule if two objects are equal they should return the same hashCode.
here is a simple implementation
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(obj == null || obj.getClass()!= this.getClass())
return false;
BinInternacionalMarcaDEL binInternacionalMarcaDEL = (BinInternacionalMarcaDEL)obj;
return (national.getNumRangoini().compareTo(this.getNumRangoini()) == 0);
}
#Override
public int hashCode() {
return this.getNumRangoini().intValue();
}

How to remove duplicates from an ArrayLlist of ArrayLists that are composed of custom objects

I have a recursive function that generates a list of lists that keeps tracks of valid hand combinations for a card game:
List<List<HandComponent>> validSCompArrangements = new ArrayList<>();
This list is populated by the recursive function successfully but often has duplicate sub-lists (by content but not by not order) that are unavoidable due to the required nature of the function. I wish to remove these duplicate sub-list entries (List<\HandComponent>) so that the above list in the end only features sub-lists that are unique in content, as order does not matter.
Here is the important part of the HandComponent class:
public class HandComponent {
private Type mType;
private Card mCard; // For runs this is the middle card
private Source mSource;
public HandComponent(Type type, Card card, Source source)
{
init(type, card, source);
}
public enum Type {PAIR, TRIPLE, QUAD, RUN}
public enum Source {STOLEN, SECRET, EITHER}
...
}
A sub-list List should only be considered equal to another sub-list if it contains the same exact HandComponents (i.e. the Type, Card, and Source between components of each list must be the same). Card is another enum defined in another file.
So, if two lists in "validSCompArrangements" are
(PAIR,CARD1,STOLEN), (TRIPLE,CARD7,STOLEN), (RUN, CARD8, SECRET)
and
(TRIPLE,CARD7,STOLEN), (RUN, CARD8, SECRET), (PAIR,CARD1, STOLEN)
they should be considered the same since they ultimately contain the same HandComponents even though the order is different and one should be removed so that "validSCompArrangements" only contains that unique list once.
Looking into this I've found bits and pieces on how to solve this problem but nothing that features this combination of a list of lists with custom objects.
One method seems to be to implement a custom Comparator that compares HandComponent instances to use with Collections in order to sort the sub-lists and then another custom Comparator to compare these sorted sub-lists for duplicates, though that seems a tad clunky and I'm not entirely sure how to override the compare method and what kind of return it expects for each comparator I'd need to make. The only other thing I've seen gestured at is that since for my usage the order of both the sub-lists and the main "validSCompArrangements" list itself don't matter, that I should be using Sets and a HashSet to solve this problem instead, I have no idea how to use those to fix this issue, other than that I might need to override the hashCode and equals methods for my HandComponent class, again, not being sure how to do so.
Overall I'm just a bit confused since any example I can manage to find thats remotely related to this usually is talking about just one list of custom objects that contain primatives and not enums, or a list of lists that uses only primatives and no custom objects at all. The fact this is a list of lists of custom objects who's members are enums has me a tad lost on how to go about this.
For example the marked answer in this question: Using collection to remove duplicate Lists, that only handles a portion of my problem, doesn't even seem to work for me despite the OP saying it does. Running that code as is, other than changing
Set<Integer> dedupedCollection = new HashSet<Integer>();
to
Set<List<Integer>> dedupedCollection = new HashSet<>();
as it was clearly meant to be, produces a collection of 3 entries where the second entry of 5, 10, 5 isn't seen as a duplicate and ignored as the OP suggested it should.
EDIT:
So far the closest thing I've found is converting my top-level list to a HashSet using:
Set<List<HandComponent>> handSet = new HashSet<>(validSCompArrangments);
but this only eliminates duplicate lists if their order is the same (which I am guessing is due to the nature of List's default implementation of "equals()"), while I need it to consider lists that are the same in content but different in order as duplicates also. One way around this would be to use Sets for the HandComponent sub-lists as well since they don't care about order innately, but this would prevent those sets from having duplicate HandComponents which I do need to be allowed.
As you said, you just need to implement equals :)
I've provided you how to implement equals method in the HandComponent class and how to use HashSet to getting only the combinations without duplicates.
I've implemented it in Java 8, you can also try to change it using for loop if you want :)
Here is the equals implementation of `HandComponent
public class HandComponent {
public enum Type {PAIR, TRIPLE, QUAD, RUN}
public enum Source {STOLEN, SECRET, EITHER}
public enum Card {ACE, ONE, TWO, TRHEE}
private Type type;
private Card card;
private Source source;
public HandComponent(Type type, Card card, Source source) {
this.type = type;
this.card = card;
this.source = source;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof HandComponent)) {
return false;
}
HandComponent handComponent = (HandComponent) o;
if (type != handComponent.type) {
return false;
}
if (card != handComponent.card) {
return false;
}
if (source != handComponent.source) {
return false;
}
return true;
}
#Override
public String toString() {
return "HandComponent=[" + String.join(", ", Arrays.asList(type.toString(), card.toString(), source.toString())) + "]";
}
}
And below you can see how you can use it
public class Main {
public static void main(String[] args) {
// Creating 2 hand components
HandComponent handComponent1 = new HandComponent(HandComponent.Type.PAIR, HandComponent.Card.ACE, HandComponent.Source.STOLEN);
HandComponent handComponent2 = new HandComponent(HandComponent.Type.QUAD, HandComponent.Card.TRHEE, HandComponent.Source.EITHER);
// 2 combinations with the same card, but different order => they are the same
List<HandComponent> firstCombination = Arrays.asList(handComponent1, handComponent2);
List<HandComponent> secondCombination = Arrays.asList(handComponent2, handComponent1);
// Mixing 2 combinations together
List<List<HandComponent>> combinations = Arrays.asList(firstCombination, secondCombination);
// printing the mix
System.out.println("Before: " + combinations);
// removing duplicates
List<ArrayList<HandComponent>> collect = combinations.stream() // having a stream of list<HandComponent>
.map(HashSet::new) // converting to HashSet, which mean there won't be duplicate in the combinations.
.distinct() // getting only the distinct combinations
.map(ArrayList::new) // reconverting to array list
.collect(Collectors.toList()); // collecting them as list
// result without duplicates
System.out.println("After: " + collect);
// You can now implement it with loop and no java 8 :)
}
}
What ended up working best for me was to implement the "equals()" method for my HandComponent class as suggested by Jiajie Xu, along with the "hashCode()" method automatically generated by Android Studio by using the option in the context menu or Alt + Insert:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HandComponent that = (HandComponent) o;
return mType == that.mType &&
mCard == that.mCard &&
mSource == that.mSource;
}
#Override
public int hashCode() {
return Objects.hash(mType, mCard, mSource);
}
I then also made the class implement the Comparable interface for use with the Collections class and specified the sort order priority of HandComponent instances within the "compareTo()" method like so:
#Override
public int compareTo(#NonNull HandComponent other) {
// Check Type first
int compareResult = mType.compareTo(other.mType);
if(compareResult == 0)
{
// Check Card second
compareResult = mCard.compareTo(other.mCard);
if(compareResult == 0)
{
// Check Source last
compareResult = mSource.compareTo(other.mSource);
}
}
return compareResult;
}
Since the default implementation of Comparable for List requires list order to be the same in order to return "true" when comparing two lists, I needed to sort my List of Lists every time I wanted to remove duplicates, which was perfectly fine as I benefited from the organization later on.
Ultimately, this allowed me remove the duplicates from my List of Lists of custom objects by first making sure the sub-lists of HandComponent were all sorted and then creating a HashSet of the top-level list.
List<List<HandComponent>> unsortedList = new ArrayList<>();
... // Populate list
for(int i = 0; i < unsortedList.size(); i++)
{
Collections.sort(unsortedList.get(i));
}
Set<List<HandComponent>> sortedDeDupedSet = new HashSet<>(unsortedList);
// Convert back to list since I need order to matter again later on
List<List<HandComponenet>> sortedDeDupedList = new ArrayList<>(sortedDeDupedSet);
This correctly removes duplicates from the top-level list now that I have properly implemented the "equals()" and "hashCode()" methods, as well as sorted the lists before hand with "compareTo()" by leveraging List's default Comparable implementation. Having to use a for loop to sort the lists themselves since I'm restricted to Java 7 does feel a little bad, but like I said before ultimately it was useful to have the lists sorted for other purposes and a lot of time and code is still saved from using a HashSet, versus the nested for loops that would be required to compare each List entry manually.

Can I use Set collection to eliminate duplicate by two different equals?

I have a project in Java. First I need to create a collection with no duplicates in the name of object & its number, so I use the Set collection and this equals method:
public boolean equals(Object obj) {
Course<?> c=(Course<?>)obj;
return (c.number==number&& c.Name.equals(Name));
}
next ..i need to create collection of the same object but now i need to insure that only his name is not duplicate. so its a problem because i cant use two diffrents methods of equals
what can i do??
I'd use a TreeSet instead and specifying the comparator to use for that specific set instead of overriding equals.
https://docs.oracle.com/javase/8/docs/api/java/util/TreeSet.html#TreeSet-java.util.Comparator-
If you don't want them actually sorted, but just remove dupes, the comparator just has to return 0 when they are equal.
TreeSet<Course> tree1 = new TreeSet<Course>((c1, c2) -> c1.number==c2.number && c1.Name.equals(c2.Name) ? 0 : 1);
and
TreeSet<Course> tree2 = new TreeSet<Course>((c1, c2) -> c1.Name.equals(c2.Name) ? 0 : 1);
You can wrap your class in a wrapper class that will implement the hashcode and equals functions the way you want:
public NameWrapper {
private Course c;
public NameWrapper(Course c) {
this.c = c;
}
public void equals(Object other) {
// ...
return this.name.equals(other.name);
}
// + hashCode
// + getter
}
// Similarly with number and name wrapper
And then you can wrap, distinct and unwrap your elements:
Collection<Course> courses = // ...
Collection<Course> distincts =
courses.stream()
.map(NameWrapper::new) // wrap
.distinct()
.map(NameWrapper::getCourse) // unwrap
.map(NumberNameWrapper::new) // wrap
.distinct()
.map(NumberNameWrapper::getCourse) // unwrap
.collect(Collectors.toList())
One easy, but probably not really great solution would be to use two specific wrapper classes that each have different equals methods.
And instead of directly using your own class, you put objects of those "wrapper" classes into those collections.
Like:
class Course { ... your class
class CourseWrapperForName {
Course wrappedCourse;
...
Course getWrappedCourse() { return wrappedCourse; }
#Override
public boolean equals(Object other) {
... compares names
class CourseWrapperForNumber {
Course wrappedCourse;
...
#Override
public boolean equals(Object other) {
... compares numbers
Now, eliminating duplicates can be done by putting your Course objects into the corresponding wrapper; adding wrappers to Sets; and then retrieving the course.
But obviously, that is a lot of boilerplate; and more reasonable solutions could be
A) using a TreeSet with a different
B) the later can be enhanced with a lot of black lambda magic; there is a nice presentation how to do that (it is in German, but mainly code; the interesting part starts at page 40).
I would take the Set<Course> with this equals method implemented (that will give me the course which are unique in name & number both).
Further, I would make a subclass of Course 'SubCourse' and override the equals method:
class SubCourse extends Course{
public boolean equals(Object o){
if(o instanceof SubCourse){
return (this.Name.equals(((SubCourse)o).Name));
}else{
return false;
}
}
}
And then make a Set<SubCourse> that will give you a unique courses in terms of numbers (not in name as we excluded that condition). You need to make the instance variables of Course as protected.

Compare 2 List of objects java

I need to compare 2 Lists of the same type of object. Can I get suggestion on which is the fastest method.
E.g
public class Cars {
String engine;
String brand;
String etc ..;
I got method compareCars(List a, List b) that returns true if there is a single occurrence in which the Cars in both are the same.
First of all, Class name should be singular - Car.
I suggest the following code.
You can override hashCode() and equals() to get compare two cars as you wanted.
boolean compareCars(List<Car> cars1, List<Car> cars2) {
boolean isSingleOccuranceMatch = false;
for (Car car : cars1) {
if (cars2.contains(car)) {
isSingleOccuranceMatch = true;
break;
}
}
return isSingleOccuranceMatch;
}
No need of variable isSingleoccuranceMatch.
This is just for readability.
You can directly return true instead of break and return false after completing all the iterations.
Using Java8, no need of any method
cars1.stream().filter(car1 -> cars2.contains(car1) ).count() > 0

Java HashSet contains Object

I made my own class with an overridden equals method which just checks, if the names (attributes in the class) are equal. Now I store some instances of that class in a HashSet so that there are no instances with the same names in the HashSet.
My Question: How is it possible to check if the HashSet contains such an object. .contains() wont work in that case, because it works with the .equals() method. I want to check if it is really the same object.
edit:
package testprogram;
import java.util.HashSet;
import java.util.Set;
public class Example {
private static final Set<Example> set = new HashSet<Example>();
private final String name;
private int example;
public Example(String name, int example) {
this.name = name;
this.example = example;
set.add(this);
}
public boolean isThisInList() {
return set.contains(this);
//will return true if this is just equal to any instance in the list
//but it should not
//it should return true if the object is really in the list
}
public boolean remove() {
return set.remove(this);
}
//Override equals and hashCode
}
Sorry, my english skills are not very well. Please feel free to ask again if you don't understand what I mean.
In your situation, the only way to tell if a particular instance of an object is contained in the HashSet, is to iterate the contents of the HashSet, and compare the object identities ( using the == operator instead of the equals() method).
Something like:
boolean isObjectInSet(Object object, Set<? extends Object> set) {
boolean result = false;
for(Object o : set) {
if(o == object) {
result = true;
break;
}
}
return result;
}
The way to check if objects are the same object is by comparing them with == to see that the object references are equal.
Kind Greetings,
Frank
You will have to override the hashCode method also.
try this..
Considering only one property 'name' of your Objects to maintain uniqueness.
#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;
}
User other = (User) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
I made my own class with an overridden equals method which just checks, if the names (attributes in the class) are equal.
This breaks the contract of .equals, and you must never do it no matter how convenient it seems.
Instead, if you want to index and look up elements by a certain attribute such as the name, use a HashMap<Name, YourType> to find them. Alternatively, use a TreeSet and pass it a Comparator that compares the name only. You can then remove the incorrect equals method.
There are then three ways if you want to find objects by reference equality:
Your objects have no inherent or useful notion of equality.
Don't implement equals. Leave it to its default. You can then use a HashSet to look for reference equality, and a HashMap or TreeSet to index them by any specific attributes.
Your objects do have a useful, universal notion of equality, but you want to find equivalent instances efficiently anyways.
This is almost never the case. However, you can use e.g. an Apache IdentityMap.
You don't care about efficiency.
Use a for loop and == every element.
HashSet contains uses the equals method to determine if the object is contained - and duplicates are not kept within the HashSet.
Assuming your equals and hashcode are only using a name field...
HashSet<MyObject> objectSet = new HashSet<MyObject>();
MyObject name1Object = new MyObject("name1");
objectSet.add(new MyObject("name1"));
objectSet.add(name1Object);
objectSet.add(new MyObject("name2"));
//HashSet now contains 2 objects, name1Object and the new name2 object
//HashSets do not hold duplicate objects (name1Object and the new object with name1 would be considered duplicates)
objectSet.contains(new MyObject("name1")) // returns true
objectSet.contains(name1Object) // returns true
objectSet.contains(new MyObject("name2")) // returns true
objectSet.contains(new MyObject("name3")) // returns false
If you wanted to check if the object in the HashSet is the exact object you are comparing you would have to pull it out and compare it directly using ==
for (MyObject o : objectSet)
{
if (o == name1Object)
{
return true;
}
}
If you do this alot for specific objects it might be easier to use a HashMap so you don't have to iterate through the list to grab a specific named Object. May be worth looking into for you because then you could do something like this:
(objectMap.get("name") == myNameObject) // with a HashMap<String, MyNameObject> where "name" is the key string.

Categories

Resources