|  | |  |
07-13-2004, 10:32 AM
|
#1 (permalink)
| | Moderator
Join Date: May 2002 Location: us.ca
Posts: 4,530
| sorting objects arrays by object properties does anyone know a good article or an easy way to sort an array of objects by any string parameter of that object?
for example, a user object:
user.firstName
user.lastName
if i have an array of users, i want to be able to sort that array based on either first or last name.
__________________ Mike |
| |
07-13-2004, 10:53 AM
|
#2 (permalink)
| | Java fanboy
Join Date: Aug 2003
Posts: 1,175
| Create a Comparator object, and use Arrays.sort(). |
| |
07-14-2004, 07:47 PM
|
#3 (permalink)
| | Centurion Nova Prime
Join Date: May 2002 Location: Oak Park, IL (USA)
Posts: 287
| I think Belisarius and I have been on opposite sides of this discussion before...or maybe it was someone else.  I like the Comparable interface better than comparators. (see Sorting Objects Tutorial)
The problem is that whatever you do, you will have to define how to do the sort on a particular object variable beforehand. Being able to pick "any" string parameter is tough.
In my tutorial, I call a method called strangeFactor(). One approach would be to use a static variable to indicate which object variable to sort by and then have your code branch on that value. If you stick that code in a method like strangeFactor(), you can keep the actual compare simple.
If you're feeling really adventurous, I suspect you can make the solution more generic by using the reflection api to get the field/variable names and values for a given object. You'll still want to use a static class variable to set the sort field name. If the datatypes are something other than String, you'll also have to look at the datatype of the sort field and have code to handle the differences in comparisons, if any.
Belisarius will probably point out that if you use reflection to go this generic, a comparator is an excellent choice. Oh, well.  |
| |
07-14-2004, 08:21 PM
|
#4 (permalink)
| | Java fanboy
Join Date: Aug 2003
Posts: 1,175
| I've actually done it both ways, and I found I prefer the Comparator route because Comparable always seemed to me the preferred way to define the natural ordering of the objects, whereas Comparator is best when you want to sort objects by different criteria. Setting a static field for the purposes of sorting is a bad idea, IMHO, as it will cause headaches in a multi-threaded environment. Say you want to sort one array of objects in manner A in thread #1, and a different array in manner B in thread #2. Doing it statically really screws you.
I generally just create an anonymous Comparator class for the job. It's atomic, so no problems with multi-threaded, plus you don't need to worry about altering the original class should you want to sort by a different criteria in the future. |
| |
07-14-2004, 08:22 PM
|
#5 (permalink)
| | Java fanboy
Join Date: Aug 2003
Posts: 1,175
| Oh, and I've never used reflection. I honestly don't know that much about it. The entire thing strikes me a really cool hack, but something that generally can (and probably should) be avoided. |
| |
07-14-2004, 08:55 PM
|
#6 (permalink)
| | Moderator
Join Date: May 2002 Location: us.ca
Posts: 4,530
| omg, i didn't even look at our java tutorials .. i guess i'll spend time there too. i haven't even tried this stuff yet .. i've been side tracked, but i will work with them tomorrow.
thanks
__________________ Mike |
| |
07-14-2004, 09:09 PM
|
#7 (permalink)
| | Centurion Nova Prime
Join Date: May 2002 Location: Oak Park, IL (USA)
Posts: 287
| My biggest issue with Comparator has always been that it doesn't feel as object oriented as implementing an interface. I like having the method for comparing the objects as part of the object. In the end, I know it's just my personal preference.
Yeah, even Sun will recommend that you don't use reflection unless you absolutely have to. The sort on any string question though makes me want to write it just to see how well it works.
The use of static variables (IMO) have their place. There are certainly limitations and gotchas that you rightly pointed out. In this case, I'm only talking about holding the name of the field that will be sorted on, not the actual values, but under the right circumstances, I suppose that could be an issue. You could just as easily hold the "sort field name" outside the class, it just appeals to my sense of order when using Comparable that the value be accessible within the class/object.
Later. |
| |
07-15-2004, 03:55 AM
|
#8 (permalink)
| | Java fanboy
Join Date: Aug 2003
Posts: 1,175
| The only way I can think of to hold it outside the class is with a singleton, at which point you've just really raised the complexity just to sort.
Like I said, I use Comparable to enforce natural ordering, but if I want to sort in more than one way, I use Comparator. Granted, it is a bit of a hack designed to pass a method to a method, but it simply is the way to go when using different sort methods on the same object. |
| |
07-15-2004, 04:30 PM
|
#9 (permalink)
| | Moderator
Join Date: May 2002 Location: us.ca
Posts: 4,530
| i ended up getting the comparator object to work because it was the easiest.
thanks!
__________________ Mike |
| |
07-21-2004, 03:09 PM
|
#10 (permalink)
| | Centurion Nova Prime
Join Date: May 2002 Location: Oak Park, IL (USA)
Posts: 287
| Generic String Comparator I spent the last few days in an Oracle Database Security class. I had a little free time in between and decided to see how much work would be required to do this sort thing. Surprisingly, not as much as I thought.
For anyone interested, StringComparator allows you to sort on any public member variable or method. I made some choices based on my own preferences here that could easily be coded a different way. (See code below)
The requirements are simple.
StringComparator strComp = new StringComparator(Object sample, String sortbyme, String sorttype);
creates the Comparator object. "sample" is an object of the type that will be sorted. "sortbyme" is the case-sensitive name of the field or method that will be used to drive the sort. "sorttype" is either "string" or "method" indicating the obvious. The fields and/or methods used for sorting must evaluate as a String. (I have to add code to prevent other types.)
The code could use a few checks here and there, but works fairly well so far in limited testing. I would appreciate any comments, suggestions, etc. Code: import java.util.*;
import java.lang.reflect.*;
public class StringComparator implements Comparator{
Field[] publicFields;
Method[] theMethods;
Class[] parameterTypes;
Vector methvec;
Vector fieldvec;
String sortBy = "";
String sortType = "string";
boolean nameMatch = true;
int methodIndex = 0;
/** Creates a new instance of StringComparator */
public StringComparator() {
}
public StringComparator(Object sample, String sortbyme, String sorttype) {
sortBy = sortbyme;
sortType = sorttype;
Class c0 = sample.getClass(); //get sample class
methvec = new Vector();
fieldvec = new Vector();
String tempName = "";
theMethods = c0.getMethods();
for (int i = 0; i < theMethods.length; i++) {
tempName = theMethods[i].getName();
methvec.add(tempName);
if (tempName.equals(sortBy)) {
parameterTypes = theMethods[i].getParameterTypes();
methodIndex = i;
}
}
publicFields = c0.getFields();
for (int i = 0; i < publicFields.length; i++) {
fieldvec.add(publicFields[i].getName());
}
if (sortType.equals("string")) {
nameMatch = fieldvec.contains(sortBy);
}
if (sortType.equals("method")) {
nameMatch = methvec.contains(sortBy);
}
} // end of constructor
public boolean isValid() {
return nameMatch;
}
public void setSortBy(String sortbyme) {
sortBy = sortbyme;
}
public String getSortBy() {
return sortBy;
}
public int compare(Object obj1, Object obj2) {
Class c1 = obj1.getClass();
Class c2 = obj2.getClass();
String str1val = "";
String str2val = "";
if (sortType.equals("string")) {
try {
Field str1 = c1.getField(getSortBy());
Field str2 = c2.getField(getSortBy());
str1val = (String) str1.get(obj1);
str2val = (String) str2.get(obj2);
} catch (Exception e) {
System.out.println(e);
}
}
if (sortType.equals("method")) {
try {
str1val = (String) theMethods[methodIndex].invoke(obj1, parameterTypes);
str2val = (String) theMethods[methodIndex].invoke(obj2, parameterTypes);
} catch (IllegalAccessException e) {
System.out.println(e);
} catch (InvocationTargetException e) {
System.out.println(e);
}
}
return str1val.compareTo(str2val);
}
} I was concerned about overhead. So one of the choices I made was to pre-populate a lot of the metadata from the reflection api during construction of the object. This moved repetitive calls out of the actual compare() method. I will probably do some timing comparisons on say a 10,000 object array to see how it stacks up to a normal Comparator for the same task...when I get some more time anyway. |
| |
07-21-2004, 05:06 PM
|
#11 (permalink)
| | Java fanboy
Join Date: Aug 2003
Posts: 1,175
| Not to put down what is actually a pretty cool bit of coding, but there's an inheirent problem for those looking to implement this; you're moving possible compilation errors to runtime. Whereas if you mistype a field-name if you accessed it through a field or method it wouldn't compile, with this you wouldn't know a problem exists until you attempted to run the code that contained the error. |
| |
07-21-2004, 07:10 PM
|
#12 (permalink)
| | Centurion Nova Prime
Join Date: May 2002 Location: Oak Park, IL (USA)
Posts: 287
| Yep. A very valid point. Unfortunately, that's the trade off when using a metadata driven solution (in this case reflection). I was worried about that when I added the isValid() method as a runtime check to return whether the name passed in matched any of the public fields/methods in the class definition, but it's still runtime. My biggest concern is non-string fields and methods. I can get around that as well by checking class and return types.
In my sample program, I actually use it this way: Code: StringComparator strcomp = new StringComparator(p1, "getFullName", "method");
if (strcomp.isValid()) {
Collections.sort(testvec, strcomp);
}else{
//do something useful here
} I just had another thought. Since the valid list of field and method names is stored within the Comparator object, I could make those items available so that they could populate a drop down in a GUI or something. That would eliminate typos as a source of error, at least in that type of app.
Thanks for the feedback! This is mostly an exercise in seeing if it could be done, but I might just use it.  |
| |
07-27-2004, 12:09 PM
|
#13 (permalink)
| | Centurion Nova Prime
Join Date: May 2002 Location: Oak Park, IL (USA)
Posts: 287
| A quick update. I did some speed tests creating Vectors of Person objects of various sizes and sorting the Vectors using a traditional Comparator vs the generic StringComparator. The Un-Scientific Results: Up to about 10,000 objects, sort speed is fairly close between the two approaches. The traditional route is usually faster, but not always and not by much. Go above 10,000 objects and you see a roughly 10 - 12% overhead associated with the generic method. For example, I ran a sort of 100,000 objects:
-- Traditional ==> 4.0 secs
-- Generic ==> 4.5 secs
Repeated tests varied over a range, but were generally within 10 - 12%.
Your mileage may vary. |
| |
07-27-2004, 04:05 PM
|
#14 (permalink)
| | [code][/code] enforcer
Join Date: Mar 2003 Location: Netherlands
Posts: 1,544
| Quote: |
I like having the method for comparing the objects as part of the object.
| This by now quite a standard in OO techniques. No need to know Java, C++ or any OO-paradigm-able language.
By using this method you'll be able to make more generic classes, and therefore loosening up the coupling between the various classes.
A recent member (grid) in the C++ forum accepted a challenge. The issue I just mentioned will play a role. After this weekend (most likely) I'll demonstrate the code.
Another method one could use is to be found in design patterns. If you are familiar with the template method pattern and/or strategy pattern, then see if it fits sde's needs. It will be one heck of elegant and OO-based solution. Note that the sorting machine doesn't have to know what it is sorting.
__________________ |
| |
07-27-2004, 07:44 PM
|
#15 (permalink)
| | Java fanboy
Join Date: Aug 2003
Posts: 1,175
| I guess you lost me Val. I'm not sure just how much more abstract you can get than a Comparable or Comparator in Java. |
| | | Thread Tools | | | | Display Modes | Linear Mode |
Posting Rules
| You may not post new threads You may not post replies You may not post attachments You may not edit your posts HTML code is Off | | | All times are GMT -8. The time now is 12:28 AM. |
Copyright © 2000-2008, Milano Interactive Web Hosting provided by Portal 360 Web Hosting |  | |