Link to home
Start Free TrialLog in
Avatar of Gregg
GreggFlag for United States of America

asked on

Question about Comparators

Is it possible to use the same Comparator class to compare any attribute of type String?

Example:
I have a person object with attributes:

String: firstName, lastName, address1, city, state, zip

Integer: personID

Id like to be able to sort by any one attribute (firstname, lastname, and city for example).

Do i create a comparator class for each? FirstNameComparator, LastNameComparator, CityComparator, etc...

Or is it possible to create a comparator that accepts string? Is that what generics does?

Thanks!
Avatar of for_yan
for_yan
Flag of United States of America image

You can have parameter set up in the constructor of yur comparator which will speify wjich attribute to us in comparison
Just include instance varaible say flag into your comparator abnd set it up n the constructor and then use this flag in compae() methiod to determine which field to use for comparison
Public class MyComp {
Int flag;
Public MyComp(int I){
This.flag = I;
}

Public int compare(Person p1, Person p2){
If(flag == 0){
// do comnparison on name
} Else if flag == 1 {
// do comparison on age
}
//etc
}

And theen you just say
Collections.sort(arraylis, new MyComp(0));
In anoteer case yiu crerate MyComp(1) etc.

Sorry for wrong case of the characcters in the coe above - this is mobile tricks
 Ffrom my pohone
- hope you get the idxea

You sure can have compaator on Strings but in this acse it will be more convenient to have comparator on Person but with this flag parameter
Avatar of CEHJ
You can use reflection to sort on any field you name. Here's a simple example:

https://suif.stanford.edu/svn/prpl/prpl_core/trunk/src/java/edu/stanford/prpl/common/GenComparator.java
SOLUTION
Avatar of for_yan
for_yan
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Gregg

ASKER

Thanks guys! Im looking into both options.

CEHJ: I find your example interesting. Is it a generally accepted approach? That would allow for me to use the Comparator for many custom classes and not have to recreate code like i did below - would you agree?

And since my last post, i put this together. I havent tested yet - it follows for_yans thought process. for_yan, what do you think?

package util.sort;

import java.util.Comparator;
import logic.Contact;

/**
 * This class represents a Comparator object for sorting
 * two contacts. The attribute to sort by is passed in
 * via constructor.
 */
public class SortBy implements Comparator<Contact> {

	//Attribute that holds selection passed in constructor.
	private SortByField whichToSort;
	
	//Constructor
	/**
	 * Constructor that accepts one parameter. 
	 * @param whichToSort This is the value to sort by.
	 */
	public SortBy(SortByField whichToSort)
	{
		this.whichToSort = whichToSort;
	}

	/**
	 * Compare two contacts based on the Sort Field Enum Selection 
	 * passed into Constructor.
	 */
	@Override
	public int compare(Contact contact1, Contact contact2) {
		
		int result = 0;
		
		if(this.whichToSort.equals(SortByField.FIRST_NAME))
		{
			result = contact1.getFirstName().compareTo(contact2.getFirstName());
		}
		else if(this.whichToSort.equals(SortByField.LAST_NAME))
		{
			result = contact1.getLastName().compareTo(contact2.getLastName());
		}
		else if(this.whichToSort.equals(SortByField.CITY))
		{
			result = contact1.getCity().compareTo(contact2.getCity());
		}
		else if(this.whichToSort.equals(SortByField.STATE))
		{
			result = contact1.getState().compareTo(contact2.getState());
		}
		else if(this.whichToSort.equals(SortByField.ZIP))
		{
			result = contact1.getZip().compareTo(contact2.getZip());
		}
		
		return result; 
	}
	
	/**
	 * This inner class represents the options for sorting.
	 */
	public enum SortByField {
		
		//Enumeration Options
		FIRST_NAME(0), 
		LAST_NAME(1),
		CITY(2),
		STATE(3),
		ZIP(4);
		
		
		private int sortByValue;
		
		//Constructor
		private SortByField(int sortByValue) 
		{
			this.sortByValue = sortByValue;
		}
		
		/**
		 * Returns the sortByField as integer.
		 * Options include: FIRST_NAME, LAST_NAME, CITY, STATE, ZIP
		 * @return sortByValue - the value representing the ENUM selection.
		 */
		public int getSortByField()
		{
			return sortByValue;
		}

	}

}

Open in new window

yes, I think it should work, the way you wrote it
In gneral the decision  will depend on your situation - if you really want to
sort all the time different classes by different fields, on the other hand sorting is defintely
not a bottleneck in your appliaction (that would be the case if you have moderatlye sized lists, which say you
first get from database - sure interaction with databse will be more of the bottleneck) then generality which you can
achivee with reflection would be of value

I still think in most of the cases folks are using more conventional way rather than doing reflection,
but if you have vwery many classes and in need of writing new comparator every other day  - then reflection will be a good choice
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>CEHJ: I find your example interesting. Is it a generally accepted approach?

Well there exist for example google classes that use reflection. The overhead of reflection is generally exaggerated, but you should always benchmark these things rather than relying on anecdote
Avatar of Gregg

ASKER

I do like the reflection example and i will explore that in more detail. I am happy to have the conventional approach working. Thank you both for taking the time to help me learn this.
:)