sorting collection wrt primitive value - java

suppose, I have a student class with roll number and name. I want to sort it out wrt roll number. I tried the following .Here is my code:
package CollectionDemo;
import java.util.*;
class student1 implements Comparable<student1>{
int rollNo;
String name;
student1(int rollNo,String name){
this.rollNo=rollNo;
this.name=name;
}
#Override
public boolean equals(Object o){
if((o instanceof student1) && (((student1)o).rollNo == rollNo)){
return true;
}
else
{
return false;
}
}
#Override
public int hashCode(){
return 1;
}
public int compareTo(student1 s) {
return s.rollNo;
}
public String toString(){
return "["+rollNo+","+name+"]";
}
}
public class treeSetDemo {
public static void main(String... a){
Set<student1> set=new TreeSet<student1>();
set.add(new student1(102,"Anu"));
set.add(new student1(101,"Tanu"));
set.add(new student1(103,"Minu"));
System.out.println("elements:"+set);
}
}
o/p: elements:[[102,Anu], [101,Tanu], [103,Minu]]
so, its not sorting:( how to make it correct .
thanks for your help.
================================================
thanks for all your help. The following code runs fine, but now I want to know how it works, if i comment out equals and hashcode method.
package CollectionDemo;
import java.util.*;
class student1 implements Comparable<student1>{
int rollNo;
String name;
student1(int rollNo,String name){
this.rollNo=rollNo;
this.name=name;
}
/* #Override
public boolean equals(Object o){
if((o instanceof student1) && (((student1)o).rollNo == rollNo)){
return true;
}
else
{
return false;
}
}
#Override
public int hashCode(){
return 1;
}
*/
public int compareTo(student1 s) {
System.out.println("hello:"+(this.rollNo-s.rollNo));
return this.rollNo-s.rollNo;
}
public String toString(){
return "["+rollNo+","+name+"]";
}
}
public class treeSetDemo {
public static void main(String... a){
Set<student1> set=new TreeSet<student1>();
set.add(new student1(102,"Anu"));
set.add(new student1(101,"Tanu"));
set.add(new student1(103,"Minu"));
System.out.println("elements:"+set);
}
}
OP:
run:
hello:-1
hello:1
elements:[[101,Tanu], [102,Anu], [103,Minu]]
BUILD SUCCESSFUL (total time: 0 seconds)

you have to change compareTo method in bellow way
public int compareTo(student1 s) {
if(s.rollNo == this.rollNo){
return 0;
}else if(s.rollNo > this.rollNo){
return -1;
}else{
return 1;
}
}

- If you want to sort on the basis of only one attribute, then go with java.lang.Comparable<T> Intereface, along with Collections.sort(List l).
- But if you aim is to sort it on the basis of more then one attribute then go for java.util.Comparator<T> along with Collections.sort(List l, Comparator c).
Eg:
import java.util.Comparator;
public class Fruit implements Comparable<Fruit>{
private String fruitName;
private String fruitDesc;
private int quantity;
public Fruit(String fruitName, String fruitDesc, int quantity) {
super();
this.fruitName = fruitName;
this.fruitDesc = fruitDesc;
this.quantity = quantity;
}
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
public String getFruitDesc() {
return fruitDesc;
}
public void setFruitDesc(String fruitDesc) {
this.fruitDesc = fruitDesc;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public int compareTo(Fruit compareFruit) {
int compareQuantity = ((Fruit) compareFruit).getQuantity();
//ascending order
return this.quantity - compareQuantity;
//descending order
//return compareQuantity - this.quantity;
}
public static Comparator<Fruit> FruitNameComparator
= new Comparator<Fruit>() {
public int compare(Fruit fruit1, Fruit fruit2) {
String fruitName1 = fruit1.getFruitName().toUpperCase();
String fruitName2 = fruit2.getFruitName().toUpperCase();
//ascending order
return fruitName1.compareTo(fruitName2);
//descending order
//return fruitName2.compareTo(fruitName1);
}
};
}

I think this implementation is close to recommended:
#Override
public int compareTo(Object other) {
if(other == null || !(other instanceOf student)){
throw new IllegalArgumentException();
}
student s = (student) other;
if(this.rollNo > s.rollNo){
return 1;
} else if (this.rollNo < s.rollNo){
return -1;
} else {
return 0;
}
}

If you are using Comparable interface then your compareTo() method should return the comparison not equals method , Google comparable example.
Check this link

In your compareTo method, you are just returning the value of the object you are comparing to. You need to return the difference, of the attribute of the invoking instance and passed instance.
So, change your compareTo method to the below one: -
#Override
public int compareTo(student1 s) {
return this.rollNo - s.rollNo;
}
NOTE: - Only sign is important for Collections.sort, so you don't really need an if-else block to return -1, 0, or 1. Just return the difference. That's all.
P.S : -
Your hashcode implementation is a very poor one. It will put every instances in the same bucket.
#Override
public int hashCode(){
return 1; // All the instances will have the same hashcode.
}
Ideally, you should use only those attributes to calculate the hashCode which you have used to compare your two instances, here its rollNo.
So, rather than returning simply a value 1, you can have some equations, that calculates your hashcode, taking into to consideration your rollNo and a large prime number also.
You can go through Effective Java - Item#9 for more explanation of this topic.
Now, that your code is working fine, lets move to your 2nd doubt.
equals and hashCode methods are not used when you want to compare two objects that will be used while sorting. We override equals and hashCode methods in order to check whether an instance is equal to another instance later on.
So, compareTo method is not concerned with whether you have ocerrided equals ad hashCode method or not. And you can also infer from name as to what the two methods does, and can they be related or not.
Moreover, equals method is defined in Object class, whereas compareTo method is declared in Comparable interface. So, they are not interrelated.
Check the documentation of these methods: - Object#equals, Object#hashCode, and Comparable#compareTo

Related

In Collections, how can i get the index using the indexOf method in the following example

class Fruit{
public String name;
Fruit(String name){
this.name = name;
}
}//end of Fruit
class FruitList{
public static void main(String [] arg5){
List<Fruit> myFruitList = new ArrayList<Fruit>();
Fruit banana = new Fruit("Banana");
//I know how to get the index of this banana
System.out.println("banana's index "+myFruitList.indexOf(banana));
//But i'm not sure how can i get the indices for the following objects
myFruitList.add(new Fruit("peach"));
myFruitList.add(new Fruit("orange"));
myFruitList.add(new Fruit("grapes"));
}//end of main
}//end of FruitList
Since the rest of the objects that i've added to the ArrayList have no references, i'm not quite sure how their index can be retrieved. Please help, Thanks so much.
It does not matter which reference the object has if you redefine the equals and hashcode methods in the Fruit class. indexOf, contains, etc use the equals(...) method to decide if the object exists inside the collection.
For example, your Fruit class, could be like this (I changed your public String name to private):
public class Fruit {
private String name;
public Fruit(String name){
this.name = name;
}
public String getName() {
return name;
}
#Override
public int hashCode() {
int hash = 7;
hash = 89 * hash + Objects.hashCode(this.name);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Fruit other = (Fruit) obj;
if (!Objects.equals(this.name, other.name)) {
return false;
}
return true;
}
Then:
Fruit f = new Fruit("orange");
myFruitList.indexOf(f); // this should return the orange fruit index (would be 1 in your example).

java Array contains object

I have
String selectedName = "ABC";
List<object> pgetName;
where object has variables such as id, name, version
I want to do the equivalent of
int first = pgetName.indexOf(selectedName);
int last = pgetName.lastIndexOf(selectedName);
as used for simple String Arrays. I've tried
int first = pgetName.getProperty("name").indexOf(processToStart);
and
int first = pgetName[].getName().indexOf(processToStart);
for example but they don't work. How do I do what I want to do? This is advanced Java for me being a noob...
Thanks in advance,
Here's an other approach (might be a little overkill but it shows you an other way). The idea is to override the indexOf and lastIndexOf method so it would verify against your field "name":
private static class TestObject {
String id, name, version;
public TestObject(String id, String name, String version) {
super();
this.id = id;
this.name = name;
this.version = version;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
}
public static void main(String[] args) {
List<TestObject> pgetName = new ArrayList<TestObject>() {
#Override
public int indexOf(Object o) {
if (o == null || this.isEmpty()) {
return -1;
}
int counter=0;
for (TestObject current : this) {
if (o.equals(current.getName())) {
return counter;
}
counter++;
}
return -1;
}
#Override
public int lastIndexOf(Object o) {
if (o == null || this.isEmpty()) {
return -1;
}
for (int i=this.size()-1; i>=0;i--) {
TestObject current = get(i);
if (o.equals(current.getName())) {
return i;
}
}
return -1;
}
};
pgetName.add(new TestObject("1", "name1", "ver1"));
pgetName.add(new TestObject("2", "name2", "ver2"));
pgetName.add(new TestObject("3", "name3", "ver3"));
pgetName.add(new TestObject("4", "name1", "ver4"));
int first = pgetName.indexOf("name1");
int last = pgetName.lastIndexOf("name1");
System.out.println("First: " + first + " - Last: " + last);
}
Result is:
First: 0 - Last: 3
For any Java object you can override the methods equals and hashCode (this is not really used but it is generally a good practice to implement both methods) in order to use the indexOf and lastIndexOf functions of java.util.List.
The contextual menu of eclipse generates a default implementation of both methods, letting you choose on which field the comparison should be done. Give it a try.
After the implementation of the methods above, you can use indexOf on List.
If I understand your question, you want to "find the index of an Object where one of the properties of the object is a specific value".
This isn't directly possible in Java (or most languages FWIW). You can achieve it pretty simply with a for loop, however:
public MyObject findObjectByName(MyObject[] objects, String name) {
for (MyObject object: objects) {
if (object.name.equal(name) {
return object;
}
}
return null;
}
If you want to find the index, you can do something similar:
public int findObjectIndex(MyObject[] objects, String name) {
for (int i = 0; i < objects.length; ++i)
if (objects[i].name.equal(name) {
return i;
}
}
return -1;
}
Now, this is the most naive approach you can take, and is often, but not always, the best approach. If you have a large number of objects, and you need to look up a lot by name, then you could be better off building an index once, and then look them up by the index:
public class MyObjectIndex {
final Map<String, MyObject> byName = new HashMap<String, MyObject>();
public MyObjectIndex(MyObject[] objects) {
for (MyObject object: objects) {
byName.put(object.getName(), object);
}
}
public getMyObjectWithName(String name) {
return byName.get(name);
}
}

.equals() method to detect duplicate array elements (tried #Override)

I have a simple loop that checks for any duplicate results,
where studresults holds my results , result is the object result given to the method and r is the current object from the array.
I have been using this method successfully throughout the program although it is not working in this case even though when I debug result and r , are exactly the same does anyone know why this might be? I have tried #Override already as suggested in other answers to no avail.
I am trying to stop duplicated array elements by throwing an exception.
for(Result r : studresults)
{
if(r.equals(result))
{
return false;
}
}
EDIT OK HERE IS THE WHOLE CLASS>
package ams.model;
import java.util.ArrayList;
import java.util.Arrays;
import ams.model.exception.EnrollmentException;
public abstract class AbstractStudent implements Student {
private int studentId;
private String studentName;
private ArrayList<Course> studcourses = new ArrayList<Course>();
private ArrayList<Result> studresults = new ArrayList<Result>();
public AbstractStudent(int studentId, String studentName) {
this.studentId = studentId;
this.studentName = studentName;
}
public String getFullName() {
return studentName;
}
public int getStudentId() {
return studentId;
}
public Result[] getResults() {
Result[] res = studresults.toArray(new Result[0]);
if(res.length > 0 )
{
return res;
}
return null;
}
public boolean addResult(Result result)
{
for(Result r : studresults)
{
if(r.equals(result))
{
return false;
}
}
studresults.add(result);
return true;
}
public void enrollIntoCourse(Course c)
{
//for re-enrollment
if(studcourses.contains(c))
{
studcourses.remove(c);
studresults.clear();
}
studcourses.add(c);
}
public void withdrawFromCourse(Course c) throws EnrollmentException
{
if(studcourses.size() > 0)
{
studcourses.remove(c);
}
else
throw new EnrollmentException();
}
public Course[] getCurrentEnrolment()
{
return studcourses.toArray(new Course[0]);
}
public abstract int calculateCurrentLoad();
public int calculateCareerPoints() {
// TODO Auto-generated method stub
return 0;
}
public String toString()
{
return studentId + ":" + studentName +":" + calculateCurrentLoad();
}
}
Do you already override hashCode method in Result?
If you override equals, you have to override the hashCode method also to allow you return the same hashcode for the similar objects (objects which has the same value but actually different object instances).
I think the default implementation of hashcode will returns different value for a different object instances even though they have the same values.
Instead I converted toString and then compared and it works???
Makes me think there was something slightly unidentical before?
New method
public boolean addResult(Result r)
{
for (Result s : studresults)
{
String sr1 = s.toString();
String sr2 = r.toString();
if(sr1.equals(sr2))
{
return false;
}
}

Sorting List<> by numeric value

I've got a public List<FriendProfile> friends = new ArrayList<FriendProfile>();. I initialize the friends list by reading the information from the server. The FriendProfile object contains a int called private int userPosition;
Once the friends list has been initialized, I would like to sort the friends list by having the FriendProfile object with the highest userPosition at index 0 of the list and then sort by accordingly, index 1 with the second highest userPosition ...
I guess I could write an sorting algorithm, yet I'm looking for prewritten code (maybe the JDK has some methods to offer?)
Help is appreciated!
Use Collections.sort() and specify a Comparator:
Collections.sort(friends,
new Comparator<FriendProfile>()
{
public int compare(FriendProfile o1,
FriendProfile o2)
{
if (o1.getUserPosition() ==
o2.getUserPosition())
{
return 0;
}
else if (o1.getUserPosition() <
o2.getUserPosition())
{
return -1;
}
return 1;
}
});
or have FriendProfile implement Comparable<FriendProfile>.
Implement Comparable Interface.
class FriendProfile implements Comparable<FriendProfile> {
private int userPosition;
#Override
public int compareTo(FriendProfile o) {
if(this.userPosition > o.userPosition){
return 1;
}
return 0;
}
}
Just Call the Collection.sort(List) method.
FriendProfile f1=new FriendProfile();
f1.userPosition=1;
FriendProfile f2=new FriendProfile();
f2.userPosition=2;
List<FriendProfile> list=new ArrayList<FriendProfile>();
list.add(f2);
list.add(f1);
Collections.sort(list);
The List will be sorted.
Now no need to Boxing (i.e no need to Creating OBJECT using new Operator use valueOf insted with compareTo of Collections.Sort..)
1)For Ascending order
Collections.sort(temp, new Comparator<XYZBean>()
{
#Override
public int compare(XYZBean lhs, XYZBean rhs) {
return Integer.valueOf(lhs.getDistance()).compareTo(rhs.getDistance());
}
});
1)For Deascending order
Collections.sort(temp, new Comparator<XYZBean>()
{
#Override
public int compare(XYZBean lhs, XYZBean rhs) {
return Integer.valueOf(rhs.getDistance()).compareTo(lhs.getDistance());
}
});
Use Collections.Sort and write a custom Comparator that compares based on userPosition.
use Comparator with Collections.sort method
java.util.Collections.sort(list, new Comparator<FriendProfile >(){
public int compare(FriendProfile a, FriendProfile b){
if(a.getUserPosition() > b.getUserPosition()){
return 1;
}else if(a.getUserPosition() > b.getUserPosition()){
return -1;
}
return 0;
}
});
see this link
There are two ways to do this.
1.
FriendProfile could implement the interface Comparable.
public class FriendProfile implements Comparable<FriendProfile>
{
public int compareTo(FriendProfile that)
{
// Descending order
return that.userPosition - this.userPosition;
}
}
...
Collections.sort(friendProfiles);
2.
You could write a Comparator.
public class FriendProfileComparator implements Comparator<FriendProfile>
{
public int compare(FriendProfile fp1, FriendProfile fp2)
{
// Descending order
return fp2.userPosition - fp1.userPosition;
}
}
...
Collections.sort(friendProfiles, new FriendProfileComparator());
When comparing objects rather than primitives note that you can delegate on to the wrapper objects compareTo. e.g. return fp2.userPosition.compareTo(fp1.userPosition)
The first one is useful if the object has a natural order that you want to implement. Such as Integer implements for numeric order, String implements for alphabetical. The second is useful if you want different orders under different circumstances.
If you write a Comparator then you need to consider where to put it. Since it has no state you could write it as a Singleton, or a static method of FriendProfile.
You can use java.lang.Comparable interface if you want to sort in only One way.
But if you want to sort in more than one way, use java.util.Compartor interface.
eg:
The class whose objects are to be Sorted on its roll_nos
public class Timet {
String name;
int roll_no;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getN() {
return roll_no;
}
public void setN(int n) {
this.roll_no = n;
}
public Timet(String name, int n) {
this.name = name;
this.roll_no = n;
}
public String toString(){
return this.getName();
}
}
The class for sorting:
public class SortClass {
public void go(){
ArrayList<Timet> arr = new ArrayList<Timet>();
arr.add(new Timet("vivek",5));
arr.add(new Timet("alexander",2));
arr.add(new Timet("catherine",15));
System.out.println("Before Sorting :"+arr);
Collections.sort(arr,new SortImp());
System.out.println("After Sorting :"+arr);
}
class SortImp implements Comparator<Timet>{
#Override
public int compare(Timet t1, Timet t2) {
return new Integer(t1.getN()).compareTo (new Integer((t2.getN())));
}
}
public static void main(String[] args){
SortClass s = new SortClass();
s.go();
}
}

How can I override equals() method using inheritance?

I have a subclass called "worker" extending the "Person" class. I am trying to override the equals() method from "Person" within the subclass of "Worker". Can anyone explain if my attempt is correct in terms of a basic override?
public class Person {
private String name;
public Person(String n) {
name = n;
}
public Person() {
this("");
}
public String getName() {
return name;
}
public String toString() {
return getName() + " ";
}
public boolean equals(Object rhs) {
if (!(rhs instanceof Person)) {
return false;
}
Person other = (Person) rhs;
return this.getName().equals(other.getName());
}
class Employee extends Person {
double salary;
public Employee(double b) {
salary = b;
}
Employee() {
salary = 150000;
}
public double getSalary() {
return salary;
}
#Override
public String toString() {
return super.toString();
}
// my attempt
#Override
public boolean equals(Object rhs) {
if (rhs == null) {
return false;
}
if (getClass() != rhs.getClass()) {
return false;
}
if (!super.equals(rhs))
return false;
else {
}
return false;
}
}
}
You've sort of mechanically handled the override part correctly, but the equals method of your Employee class will never return true.
First because of this:
if (!super.equals(rhs)) return false; else { }
You'll always fall through to the final return false, even if the result of super.equals is true.
Once you fix that, you still have a problem with the equals method of Person. If you pass in an instance of Worker, that equals method will always return false.
There may yet be other things, but those two are show stoppers.
The NetBeans using the shortcut alt + insert, you can automatically generate the equals method, constructors, getters, setters, delegate method, and others. If you want to use the collection using encoding mixing(Hashtable, HashMap, HashSet) it with redefining equals you must also redefine the hashCode().

Categories

Resources