How to compare value of array of objects? - java

There is a collection of 20 objects of a POJO class. I Want to write a method that return objects with distinct value. Now this is my Pogo class
class Student {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName( String firstName ) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName( String lastName ) {
this.lastName = lastName;
}
}
Now i want some method which returns unique last names values. I could not understand which logic i have to put in this.

If you are using something like Eclipse, you can right-click the source and select Source > "Generate hashCode() and equals()...". Doing so will yield something like this:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());
result = prime * result + ((lastName == null) ? 0 : lastName.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;
Student other = (Student) obj;
if (firstName == null) {
if (other.firstName != null)
return false;
} else if (!firstName.equals(other.firstName))
return false;
if (lastName == null) {
if (other.lastName != null)
return false;
} else if (!lastName.equals(other.lastName))
return false;
return true;
}
Then, you'll want to add your objects to an instance of Set, maybe HashSet. Sounds like you can just return the populated Set then.
See also this.
EDIT: Note that I am not suggesting to put all of this on the Student class. The code shown above goes on Student, but the method that returns the set of distinct students goes somewhere else.
EDIT 2: If you are only interested in unique last names, you could modify hashCode() and equals() to not consider first name, but I concede that this would be quite unintuitive and recommend to avoid this in any circumstance other than an academic exercise. So, more correct might be to layer on an instance of Comparator that only considers last name--see doc and this.

You can use an Arraylist, it has a built in function called .contains() which checks if the arrayList contains a specific value. So you would create an arrayList of last names and if it doesn't exist in the array list, just add it. See http://docs.oracle.com/javase/1.5.0/docs/api/java/util/ArrayList.html#contains(java.lang.Object)

You can try to use Set, if you need to get only one field, or Map, if you need to know object(student) with this field.
If you need to know all distinct Students (pair: first name + surname), you need to override getHashCode() and equals methods and use HashSet, HashMap

An easy way (for a beginner) to do this is just create a new array (same size of the input array). Then to loop through your array then compare every value to every other value in the array. If you can't find a match, then put this value in the new array.
Pseudo code:
public static Student[] GetUniqueLastNames(Student[] students){
Student[] retArray;//new array
for(i = 0; i < students.size; i++){
unique = true
for(j=0; j < students.size; j++){
if(i != j){//make sure its not comparing the same value
if(students[i].lastname.equals(students[j].lastname)){
unique = false
break
}
}
}
if(unique){
retArray[i] = students[i]
}
}
return retArray
}
Note: There are far better ways of doing this, but this is a nice basic way to do it if you're learning Java (or programming in general).

If you don't care about keeping the order of the objects, you can use a set:
public static <S extends Student> Collection<S> uniqByLastName(Collection<S> source){
TreeSet<S> result = new TreeSet<S>(new Comparator<S>() {
#Override
public int compare(S s1, S s2) {
return s1.getLastName().compareTo(s2.getLastName());
}
});
result.addAll(source);
return result;
}
If you care about the order
public static <S extends Student> Collection<S> uniqByLastName(Collection<S> source){
Collection<S> result = new ArrayList<S>();
Set<String> addedStudents = new HashSet<String>();
for(S student : source){
String lastName = student.getLastName();
if(!addedStudents.contains(lastName)){
result.add(student);
addedStudents.add(lastName);
}
}
return result;
}
If you want to modify the collection without returning a new one
public static <S extends Student> void uniqByLastName(Collection<S> source){
Set<String> addedStudents = new HashSet<String>();
Iterator<S> iterator = source.iterator();
while(iterator.hasNext()){
S student = iterator.next();
String lastName = student.getLastName();
if(addedStudents.contains(lastName)){
iterator.remove();
} else {
addedStudents.add(lastName);
}
}
}

If you are using Java 8, you can use lambda expression to solve it. Using following code snippet should solve your problem:
list.stream().collect(Collectors.toMap(Student::getLastName, p -> p, (p, q) -> p)).values();
Note: it will return first student with a given last name and as you might have already guessed, you don't need to override equals and hashcode.

Related

Duplicate Objects being stored in ArrayList with add method

I have two classes, one named Bird the other Runtime. The bird class creates birds - name, latin name. The Runtime class has 4 methods, only one is important for this question, that is the 'add' method. The add method when called upon needs to take input from the user that is name and latin name, these are saved into a string variable 'name' and 'latin name' and I call the Bird class constructor and pass in these string variables into its parameter and finally it is added to an ArrayList. However I get duplicate values, if I were to write the same bird twice.
I have tried to convert the ArrayList into a set and convert it back again into an ArrayList, i did this within the add method, this did not work. I suspect it is down to my poor understanding of how objects are stored in an ArrayList. I also created a getName method within the Bird class, so I can use list.get(i).getName, and if the name is equal to the one typed by the user, it prompts the user accordingly, if not it is added to my ArrayList. This also did not work. I also tried a for loop that would go through the ArrayList and an if statement would determine if the name typed by the user exists within the ArrayList, this also did not work, the attempt was early on so I can't remember exactly the error message, but the add method is called from within a while loop, and I think the error message was concurrent modification, I'm not entirely sure so please ignore that, my point is showing the various solutions I tried.
Below is The Bird class
public class Bird{
int obeservation = 0;
String name;
String latinName;
public Bird(String name, String latinName){
this.name = name;
this.latinName = latinName;
}
public void addBird(String name, String latinName){
this.name = name;
this.latinName = latinName;
}
public String getName(){
return this.name;
}
public String statistics(){
return this.name + " (" + this.latinName + ") : " +
this.obeservation + " observation";
}
}
Below is the Runtime class
public class Runtime {
ArrayList<Bird> birds = new ArrayList<Bird>();
Scanner scan = new Scanner(System.in);
public void scan() {
System.out.println("?");
String answer = scan.nextLine().trim();
while (!answer.equalsIgnoreCase("EXIT")) {
System.out.println("?");
answer = scan.nextLine().trim().toUpperCase();
if (answer.equalsIgnoreCase("ADD")) {
add();
} else if (answer.equalsIgnoreCase("OBSERVATION")) {
observation();
} else if (answer.equalsIgnoreCase("STATISTICS")) {
System.out.println("jhjh");//just to see if this is
working
statistics();
}
}
}
below is the add method, also what I've commented is the attempts,
currently the add method does not have an if statements to decide duplicates.
public void add() {
System.out.print("Name: ");
String name1 = scan.nextLine().trim().toUpperCase();
System.out.print("Latin Name: ");
String latinName1 = scan.nextLine().trim().toUpperCase();
birds.add(new Bird(name1, latinName1));
/*
Bird newBird = new Bird(name1, latinName1);
for (int i = 0; i < birds.size(); i++) {
if (birds.get(i).getName().equals(name)) {
System.out.println("Bird already exist");
return;
} else {
birds.add(newBird);
}
}
/*
* hBirds.addAll(birds); birds = new ArrayList<Bird>();
birds.addAll(hBirds);
*
* // Bird newBird = new Bird(name, latinName);
* /* if(birds.contains(name)){
* System.out.println("That name already exist");
* return;
* }else{
* birds.add(newBird(name, latinName));
*
* }
*/
}
The statistics method prints out the ArrayList, a foreach loop that goes through the ArrayList prints it out. The expected result if I input seagull twice should be one seagull value not two. How do i reject the duplicate?
You can have two approaches here:
First: Traverse through ArrayList, if you can't find the same bird, add it to ArrayList. It is a worse approach.
Second: Store birds inside HashSet. In this case, you need to override .hashCode() and .equals(Object obj) methods. It is a better approach.
Before talking about how to generate .hashCode() and .equals(Object obj) methods, I want to mention about .hashCode() method and HashSet<T>.
HashSet<T>s provide a unique set of the elements inside. To achieve this, .hashCode() method of a class is used. If you override .hashCode() method in any class, you can get the benefit of using HashSet<T>s. If you don't override this method, Java automatically returns the memory address of the object. That's why your HashSet<Bird> was including duplicate elements.
.hashCode() and .equals() methods can be generated by lots of IDEs. I copied and pasted your Bird class to Eclipse. By using Alt+Shift+S -> h for Eclipse or Alt+Insert -> equals() and hashCode() for IntelliJ, automatically generated the methods below:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((latinName == null) ? 0 : latinName.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + obeservation;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Bird other = (Bird) obj;
if (latinName == null) {
if (other.latinName != null)
return false;
} else if (!latinName.equals(other.latinName))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (obeservation != other.obeservation)
return false;
return true;
}
If you add these methods(I encourage you to generate in your IDE) to Bird class, you can use HashSet<Bird>. To avoid duplicates, simply add all of your Bird objects into defined HashSet<Bird>. You don't need any other data structure or equality check to control if any two Bird type objects are equal.
You will just need to change your object collection from ArrayList<Bird> birds = new ArrayList<Bird>(); to Set<Bird> birds = new HashSet<>();.
Move the add out of the loop:
for (int i = 0; i < birds.size(); i++) {
if (birds.get(i).getName().equals(name1)) {
System.out.println("Bird already exist");
return;
}
}
birds.add(new Bird(name1, latinName1));

Comparing An Entry In A Map With An Object

I have a Map in Java like so,
private HashMap<String, Object[][]> theMap;
Where the key is a String and the entry is going to be something along the line of,
theMap = new HashMap<>();
Object[][] theData = {
{Boolean.FALSE, "Text"}
};
theMap.put("Key1", theData);
Somewhere along the line I would like to check if an entry in the map is equivalent to another object. Currently I am doing it like this,
Object[][] tempData = {
{Boolean.FALSE, "Text"}
};
for(Object key: entries.keySet()) {
if(entries.get(key).equals(tempData)) {
entries.remove(key);
}
}
And it is not working.
I would prefer the comparison to be done with an object rather than with another map. I'm wondering what I'm doing wrong with this comparison here?
The reason you are not getting equality is that arrays inherit Object#equals() which is based on identity, not equality of contents. You could consider using java.util.Arrays.deepEquals(Object[], Object[]) to compare.
That is the answer to the immediate question. However, using a 2-dimensional array of Object to hold a boolean and a String is really bad code smell and indicates you need to encapsulate what you are putting in the array.
Identity vs Equivalence
Please make sure that you understand that by default the equals() method of Object checks on whether two object references are referring to the same object (identity), which is not what your code is checking.
Instead, your code is checking whether the two objects (the values you put on the map) are having the same value (equivalence).
Here are two articles about this topic:
What is the difference between identity and equality in OOP?
Overriding equals method in Java
In this particular problem of yours, I think the solution involves two steps:
Your tempData and theData does not seems to be an array
of elements of the same type (it does not appear to be a 2-dimensional
array either). Instead, it contains a Boolean value and then a
String value. In this case, I think you really should think
through what this thingy is and design a class for it (I am showing
an example below)
The class should override the equals() (and hashCode()) methods
so that you can use its equals() for equivalence checking.
Note also that your IDE (e.g. Eclipse) probably can generate a template for equals() and hashCode() for you.
Example: (here I assume your Boolean represents a condition, and your String represents a message)
class MyRecord {
private Boolean condition;
private String message;
public Boolean getCondition() {
return condition;
}
public void setCondition(Boolean condition) {
this.condition = condition;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((condition == null) ? 0 : condition.hashCode());
result = prime * result
+ ((message == null) ? 0 : message.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;
MyRecord other = (MyRecord) obj;
if (condition == null) {
if (other.condition != null)
return false;
} else if (!condition.equals(other.condition))
return false;
if (message == null) {
if (other.message != null)
return false;
} else if (!message.equals(other.message))
return false;
return true;
}
}

Comparable interface with many conditions

The Question is how can use comparable interface and collections.sort to do the sorting with model , production and price. Can i do these three sorting in ascending order within "public int compareto(car other)"?
For example, It will be sorted with model in alphabetical order. If model is same, then sorted with production in alphabetical order. if production is also same , then finally sorted with price in ascending order.
Thank you for attention, i stuck with this problem many days. Please help me.
public static void main(String[] args) {
ArrayList<Car> car = new ArrayList<car>();
// something ignored//
Collections.sort(car); <----------------------Problem
for (Car c : car) {
System.out.println(c);
}
}
class car implements Comparable<car>{
protected String model;
protected String production;
protected int price;
public Tablet(String model ,String production , int price)
{
this.model=model;
this.price=price;
this.production = production;
}
public int compareTo (car other)
{
?????????????????
}
}
class mini-bus extends car
{
private door;
public Tablet(String model ,String production , int price ,int door)
{
super(model , production , price);
this.door = door;
}
}
The principle is quite straightforward:
Compare the first pair of properties. If they are different, return the negative/positive compare value; otherwise...
Compare the second pair of properties. If they are different, return the negative/positive compare value; otherwise...
... (repeat for as many pairs of properties as you have) ...
Compare the last pair of properties. This is the last property, so return the compare value.
For example:
int compareModels = this.model.compareTo(that.model);
if (compareModels != 0) {
return compareModels;
}
int compareProd = this.production.compareTo(that.production);
if (compareProd != 0) {
return compareProd;
}
return Integer.compare(this.price, that.price);
Note that there is also a nice class in Guava called ComparisonChain which reduces a lot of this boilerplate logic:
return ComparisonChain.start()
.compare(this.model, that.model)
.compare(this.production, that.production)
.compare(this.price, that.price)
.result();
This stops comparing once a difference is found between any pair of properties. It will still access the subsequent properties, but that should hopefully be an irrelevantly cheap thing to do anyway.
Here is the general approach to the problem of multi-attribute sorting:
Decide on the ordered list of attributes by which you sort
For each attribute on your list, compare the values on both sides
If the result is not zero, return it right away
If the result is zero, go to the next attribute on your list
If you ran out of attributes, return zero
If the number of attributes is fixed, the "loop" on the ordered list of attributes is unrolled, i.e. each individual attribute is compared separately:
int res;
res = this.getA().compareTo(other.getA()); // e.g. model
if (res != 0) return res;
res = this.getB().compareTo(other.getB()); // e.g. production
if (res != 0) return res;
res = this.getC().compareTo(other.getC());
if (res != 0) return res;
...
// For the last attribute return the result directly
return this.getZ().compareTo(other.getZ()); // e.g. price
This should do:
public int compareTo(Car other){
if(this.getModel().compareTo(other.getModel()) != 0){
return this.getModel().compareTo(other.getModel());
}else if(this.getProduction().compareTo(other.getProduction()) != 0){
return this.getProduction().compareTo(other.getProduction());
}else{
return Integer.compare(this.getPrice(), other.getPrice());
}
}

Comparing two collections using hamcrest contains() method

I have two collections which I am trying to compare for equality in my unit tests, but I am struggling with the contains method. Here is what I have:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
expectedItems.add(iPhone);
expectedItems.add(skateboard);
assertThat(expectedItems, contains(actualItems));
}
items contains the same objects as expectedItems so I would expect the assertion to be true but this is the output I get:
[Item{name=iPhone}, Item{name=Skateboard}] --> Expected
[Item{name=iPhone}, Item{name=Skateboard}] --> Actual
java.lang.AssertionError:
Expected: iterable containing [<[Item{name=iPhone}, Item{name=Skateboard}]>]
but: item 0: was <Item{name=iPhone}>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)
Please can you help me where I am going wrong with using the contains method?
public class Item {
private String name;
public Item(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return Objects.toStringHelper(this).add("name", name).toString();
}
#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;
Item other = (Item) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
A Collection's .contains(...) uses the equals and hashCode methods of the Objects. In order to use equals (or in this case contains) on your own Objects, you need to override the equals and hashCode methods of your class. This is because Java uses references behind the scenes, so even though the field may be equal, the Object-references are not.
In Eclipse you can generate them using right-mouse click -> Source -> Generate hashCode() and equals().... But, since you never stated you use Eclipse, here is an example of the methods that are generated:
// Overriding this class' equals and hashCode methods for Object comparing purposes
// using the Collection's contains
// contains does the following behind the scenes: Check if both inputs aren't null,
// check if the HashCodes match, check if the Objects are equal.
// Therefore to use the Collection's contains for Objects with the same fields, we
// need to override the Object's equals and hashCode methods
// These methods below are generated by Eclipse itself using "Source -> Generate
// hashCode() and equals()..."
#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;
Item other = (Item) obj;
if(name == null){
if(other.name != null)
return false;
}
else if(!name.equals(other.name))
return false;
return true;
}
If you add both of these to your Item-class, the contains will work.
EDIT:
I'm not sure, but when I look at your code I think the following might be wrong:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
// You first print both lists
System.out.println(expectedItems);
System.out.println(items);
// And then add the two items to the expectedItems
expectedItems.add(iPhone);
expectedItems.add(skateboard);
assertThat(expectedItems, contains(actualItems));
}
If you try the following instead:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
// First add both items
expectedItems.add(iPhone);
expectedItems.add(skateboard);
// Then print both lists
System.out.println(expectedItems);
System.out.println(items);
assertThat(expectedItems, contains(actualItems));
}
Does the expectedList now contain 4 items?
[Item{name=iPhone}, Item{name=Skateboard}, Item{name=iPhone}, Item{name=Skateboard}] --> Expected
[Item{name=iPhone}, Item{name=Skateboard}] --> Actual
In that case you shouldn't add the two items, since they are already present in the list.
Also, you're trying to use the contains on the entire list. Normally the contains is used to see if a single item is present in the list. So you could either use something like this:
for(Item i : expectedList){
assertTrue(actualList.contains(i));
}
or perhaps something like this, in case you use these libraries:
assertThat(actualList, is(expectedList));
I'm not sure if this is the cause and if this will fix it, since you use a different JUnit library then I usually do and I'm not sure if these syntax with the Asserts are possible.
I really don't think you actually need hamcrest for this. Wouldn't it be easier to make the asserts in one of the following ways:
A list is still an object at the end of the day:
org.junit.Assert.assertEquals(expected, actual)
An old fashion functionality for lists by using containsAll(..):
org.junit.Assert.assertTrue(expectedItems.containsAll(actualItems))
Using asserts for arrays' equality:
org.junit.Assert.assertArrayEquals(expectedItems.toArray(), actualItems.toArray())
Of course you can use hamcrest as well:
org.hamcrest.MatcherAssert.assertThat(actual, Matchers.containsInAnyOrder(actual.toArray()));
OR
org.hamcrest.MatcherAssert.assertThat(actual, Matchers.contains(actual.toArray()));
You basically asserting that expectedItems is a list with one element and this element is expected to be a list itself with the two items iPhone and skateboard.
To assert that expectedItems and actualItems have the same elements in the same order try this:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
assertThat(actualItems, contains(iPhone, skateboard));
}
And beware that assertThat expects the "actual" object as first parameter and not the "expected".
Alternatively you can do something like that:
#Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
Collection<Item> expectedItems = Lists.newArrayList();
expectedItems.add(iPhone);
expectedItems.add(skateboard);
assertThat(actualItems, contains(expectedItems.toArray(new Item[expectedItems.size()])));
}

contains giving faulty results

I have a class 'CoAutoria' that's suposed to hold 2 instances of an 'Author' class (which only has a name, for now) and the number of articles those authors have in common.
In order to figure out the top 10 of co-authors (regarding number of articles) I created a TreeSet of 'CoAutoria', to hold the total of articles, for each pair.
I need to cycle through a Map of years, gather the different authors and their respective Set of co-Authors. Then, for each pair, create an instance of 'CoAutoria' and: add it to the treeset (if it doesn't already exists); or simply sum its number of articles to the one existing on the set.
I already created the compareTo method, to insert it on the treeset, and created the equals method so that the order of the authors doesn't matter.
Here's the main code:`
public class CoAutoria implements Comparable<CoAutoria>
{
private Autor autor1;
private Autor autor2;
private int artigosComum;
(...)
}
#Override
public int compareTo(CoAutoria a2)
{
String thisAutor1 = autor1.getNome();
String thisAutor2 = autor2.getNome();
String caAutor1 = a2.getAutor1().getNome();
String caAutor2 = a2.getAutor2().getNome();
if((autor1.equals(a2.getAutor1()) && autor2.equals(a2.getAutor2())) || (autor1.equals(a2.getAutor2()) && autor2.equals(a2.getAutor1())))
{
return 0;
}
else
{
return 1;
}
}
#Override
public boolean equals(Object o)
{
if(this == o)
{
return true;
}
if( o == null || o.getClass() != this.getClass())
return false;
CoAutoria ca = (CoAutoria) o;
String thisAutor1 = autor1.getNome();
String thisAutor2 = autor2.getNome();
String caAutor1 = ca.getAutor1().getNome();
String caAutor2 = ca.getAutor2().getNome();
if((thisAutor1.equals(caAutor1) && thisAutor2.equals(caAutor2)) || (thisAutor1.equals(caAutor2) && thisAutor2.equals(caAutor1)))
{
return true;
}
else
{
return false;
}
}
The main problem is: When I check if the set already has a certain instance of 'CoAutoria', (I'm using the contains() method of TreeSet), it gives me faulty results...sometimes it checks correctly that the Pair A-B already exists in that set (on the form of B-A), but sometimes it doesn't... For what I've read, the contains uses the equals method, so that's not suposed to happen..right?
[EDIT:]
Since the first post I started to think that maybe the problem resided on the compareTo..So I changed it to
public int compareTo(CoAutoria a2)
{
String thisAutor1 = autor1.getNome();
String thisAutor2 = autor2.getNome();
String caAutor1 = a2.getAutor1().getNome();
String caAutor2 = a2.getAutor2().getNome();
if(this.equals(a2))
{
System.out.println("return 0");
return 0;
}
else
{
int aux = thisAutor1.compareTo(caAutor1);
if(aux != 0)
{
return aux;
}
else
{
return thisAutor2.compareTo(caAutor2);
}
}
}
But it still gives my bad results..I thought I'd figured it now: if it's the same 'CoAutoria', I return 0, if not I go through the names, and order it by their compareTo values..but something's missing
Your contains method is breaking, because your compareTo method is always returning 0 or positive, no negatives. This means your compareTo is inconsistent. A correct implementation should return 0 if the authors are the same, or positive and negative values when the authors are different.
Example (assuming author1 is different than author2):
int i = author1.compareTo(author2); // i should be positive or negative
int j = author2.compareTo(author1); // j should be the opposite of i
Yours will return 1 for both of the above cases, which will make ordered Collections not work as no element is ever smaller. As another example imagine if you had a Binary Tree(an ordered collection) that had the elements [1-10]. If you were searching for the element 5, your binary tree when comparing 5 against any element would always say that it was equal or greater.
How exactly you should change it is up to you. But an idea would be to sort the authors by name, then iterate over both collections and compare the authors together lexicographically.
EDIT: Even after your edit to your methods they are still not consistent. Try the following, they aren't the most efficient but should work unless you really want to optimize for speed. Notice they first sort to make sure author1 and author2 are in order before they are compared with the other CoAutor which is also sorted. I don't do any null checking and assume both are valid authors.
#Override
public boolean equals(Object o){
if (o == null || !(o instanceof CoAutoria)) return false;
if (o == this) return true;
return this.compareTo((CoAutoria)o) == 0;
}
#Override
public int compareTo(CoAutoria o) {
List<String> authors1 = Arrays.asList(autor1.getNome(), autor2.getNome());
List<String> authors2 = Arrays.asList(o.autor1.getNome(), o.autor2.getNome());
Collections.sort(authors1);
Collections.sort(authors2);
for (int i=0;i<authors1.size();i++){
int compare = authors1.get(i).compareTo(authors2.get(i));
if (compare != 0)
return compare;
}
return 0;
}

Categories

Resources