Is the term "natural ordering" specific to Java? - java

The tutorial Object Ordering refers to the concept of "natural ordering":
If the List consists of String elements, it will be sorted into
alphabetical order. If it consists of Date elements, it will be sorted
into chronological order. How does this happen? String and Date both
implement the Comparable interface. Comparable implementations provide
a natural ordering for a class, which allows objects of that class to
be sorted automatically. The following table summarizes some of the
more important Java platform classes that implement Comparable.
Is the term "natural ordering" specific to Java, or language-independent? For example, could I talk about "natural ordering" in Ruby?
(Note: I'm not talking about Natural sort order, mentioned in Jeff Atwood's blog post Sorting for Humans : Natural Sort Order)

This is not a reference to the type of natural ordering where numbers inside of strings are sorted "naturally" instead of lexicographically digit-by-digit. Java defines the term differently.
Let's change the emphasis:
Comparable implementations provide a natural ordering for a class, which allows objects of that class to be sorted automatically.
The word "natural" means that if you implement Comparable then users of your class can sort it easily without needing a custom comparator. The sorting is natural; it's built in; it's free, no thinking required.
Is the term "natural ordering" specific to Java, or language-independent?
Yes. No. Both? It's specific to Java insofar as the documentation italicizes the term and there is a naturalOrder method. The concept is applicable to other languages, though, sure.
For example, could I talk about "natural ordering" in Ruby?
You could. If you were talking off the cuff you could use the term. If you were writing formally it would be prudent to define it. Because of the confusion with Atwood's use of the term, I'd prefer a different one. Say, "default ordering".

I believe the term has a specific meaning in Java
At least in the official documentation.
From the API doc for the Comparable interface:
This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.
If we are very familiar with this line from the API doc. Then we see a class implements the Comparable interface, and we see somewhere/somebody mentions the "natural order" of two instances of A, we know that it might be talking about the order imposed by the compareTo method. The question is, does the person saying/writing that term also knows about this specific meaning and is using it in the context?
Of course the API doc is using the term that way because the first thing it does is to define it.

No, the term natural ordering is not Java specific. My opinion is it doesn't pertain to programming languages specifically at all; rather, likely all programming languages (although they may or may not use the term explicitly) rely on the concept.
For example, how would a method like max(a, b) or a.after(b) work if there wasn't a concept of natural ordering? We know the natural order of integers: 1, 2, 3, ...; dates 1/1/1990, 1/2/1990, 1/1/1991, ...; time: 12:00, 12:01, 1:01 ... These system are human-defined but it's what we expect. If we had a number of integers ordered 1, 3, 2, 4 it would be unnatural.
Your quote, as I read it, suggests just that. A type that implements the Comparable interface provides a "default", well-defined, or expected ordering. For developer-defined types it's up to the developer to enforce the natural ordering (as Java developers did with Numbers) or define the natural ordering as we often do with complex types of our own.
When a class implements the Comparable interface it provides a compile-time (natural) ordering only to be altered by providing a custom Comparator. Still, there are a limited number of objects or systems we can represent in software that have a true, well-understood, and accepted natural order. Many types like Students, Cars, and Users can depend on one or a combination of attributes that determine their order which may not seem natural at all.

This can be achieved by implementing new Comparator<String> and pass it to Collections.sort(list, comparator) method.
#Override
public int compare(String s1, String s2) {
int len1 = s1.length();
int len2 = s2.length();
int lim = Math.min(len1, len2);
char v1[] = s1.toCharArray();
char v2[] = s2.toCharArray();
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
if(this.isInteger(c1) && this.isInteger(c2)) {
int i1 = grabContinousInteger(v1, k);
int i2 = grabContinousInteger(v2, k);
return i1 - i2;
}
return c1 - c2;
}
k++;
}
return len1 - len2;
}
private boolean isInteger(char c) {
return c >= 48 && c <= 57; // ascii value of 0-9
}
private int grabContinousInteger(char[] arr, int k) {
int i = k;
while(i < arr.length && this.isInteger(arr[i])) {
i++;
}
return Integer.parseInt(new String(arr, k, i - k));
}

Related

Comparable and Comaprator interfaces

It is generally said that comparator is used to have multiple sorting sequences of collection of objects while comparable is used to have single sorting sequence.
What is the use of comparator interface in java when it is possible to have multiple sorting sequences using comparable interface?
import java.util.*;
enum CompareValue {RollNo, Marks;}
class Student implements Comparable<Student> {
public int marks;
public int rollNo;
public static CompareValue comparator = CompareValue.RollNo;
Student (int marks, int rollNo) {
this.marks = marks;
this.rollNo = rollNo;
}
public int compareTo(Student s) {
switch (comparator) {
case RollNo:
return this.rollNo - s.rollNo;
case Marks:
return this.marks - s.marks;
}
return 0;
}
}
public class Test
{
public static void main (String[] args)
{
Student s1 = new Student(59, 103);
Student s2 = new Student(87, 102);
Student s3 = new Student(78, 101);
Student students[] = {s1, s2, s3};
Arrays.sort(students);
System.out.println("Student list sorted by rollno");
for (Student s:students) {
System.out.println(s.rollNo + " - " + s.marks);
}
Student.comparator = CompareValue.Marks;
System.out.println("Student list sorted by marks");
Arrays.sort(students);
for (Student s:students) {
System.out.println(s.rollNo + " - " + s.marks);
}
}
}
When your compareTo method has different behaviors based on the value of some static variable, you are basically introducing a global setting that controls the natural ordering of the Student class.
This could be confusing and counter intuitive to users of your class.
Besides, it makes the implementation of compareTo awkward, especially if you have more than two implementations, and each implementation depends on multiple instance variables.
Comparator is a much more suitable interface to supply multiple different comparisons for instances of the same class, each implementation having its own compare() logic.
When you have objects that do not implement comparable, but you would like to sort a collection consisting them, you would either have to extend them just to sort your collection or provide a comparator that compares them even though they are not comparable.
Or you might want to compare sort those objects in a different manner then their natural sort.
Imagine such an example.
String is an object that is comparable. Imagine you want to sort a collection of strings based on their hashCode instead of the string natural order. How would you do it without creating a comparator?
What you have shown there is indeed multiple sort orders using Comparable, but don't you think it's too much boiler plate code? Let's say if you have added a new field to the class called name, and now you want to sort by name. You'd have to:
add a new case to the enum
add a new case to the compareTo.
Another disadvantage of using the approach you showed is that it is not necessarily clear what this means:
Arrays.sort(student);
You would have to look through your code and check what value you have set the comparator.
Also, if I were using your class and I want to sort by something else, I would have to create a Comparator anyway, because I can't edit your class.
But if you use Comparator, you solve all of these problems:
Arrays.sort(students, Comparator.comparing(Student::getName));
Therefore, Comparable is only useful when there is one natural order, like dates and times for example.
If we look at the Comparable and Comparator interfaces and what they mean, everything will be clear.
Comparable:
This is an internal property of a JAVA class i.e. it assumes that whenever one uses the internal compareTo() method, one is using it for the specified object.
public int compareTo(T o);
Therefore, in implementation of this method we use this which is the current object and compare it to some other object of same type. These can be treated as defaults or use for natural ordering.
Like 1 comes before 2 and so on. This is the natural ordering.
Comparator:
This is property which actually is not tightly bound to the Java class itself. Comparators are used to actually provide a method to be used by some other services (like Collections.sort()) for achieving a particular goal.
int compare(T o1, T o2);
By this we mean, You can have multiple Comparators, providing different ways of achieving different goals wherein the actual service can pick any two objects and compare them.
This can be used to provide custom ordering, like using some equation we can come up with an ordering where f(1) actually comes after f(2) and so on. This equation will likely be achieving some order which solves a use-case.

Equivalent to stream distinct using a custom comparator

If I have the following List:
List<String> list = Arrays.asList("hello", "world", "hello");
And I apply the following (Java8):
list.stream().distinct().collect(Collectors.toString());
Then I would get a list with "hello" and "world".
However, in my case, I have a list of a type (from an external api) where I want to "bypass" the equals Method, ideally with a comparator, as it doesn't cover what I need.
Assume this class looks like this:
public class Point {
float x;
float y;
//getters and setters omitted
}
In this case, I would like two points that cover a certain criteria to be defined as equal, for instance (30, 20) and (30.0001, 19.999).
A custom comparator could do the trick, but I have found no API that does what the distinct() in Java8 Stream does, but with a comparator (or similar pattern).
Any thoughts? I know I could write such a function, but I would rather like the elegant way of using existing apis... I have no restriction with external libraries (guava, apache-commons, etc. are welcome if they have a comfortable way of doing what I need).
HashingStrategy is the concept you're looking for. It's a strategy interface that allows you to define custom implementations of equals and hashcode.
public interface HashingStrategy<E>
{
int computeHashCode(E object);
boolean equals(E object1, E object2);
}
Streams don't support hashing strategies but Eclipse Collections does. It has sets and maps that support hashing strategies as well as overloads of methods like distinct() that take hashing strategies.
This would work well for Strings. For example, here's how we could get all distinct Strings ignoring case.
MutableList<String> strings = Lists.mutable.with("Hello", "world", "HELLO", "World");
assertThat(
strings.distinct(HashingStrategies.fromFunction(String::toLowerCase)),
is(equalTo(Lists.immutable.with("Hello", "world"))));
Or you can write the hashing strategy by hand to avoid garbage creation.
HashingStrategy<String> caseInsensitive = new HashingStrategy<String>()
{
#Override
public int computeHashCode(String string)
{
int hashCode = 0;
for (int i = 0; i < string.length(); i++)
{
hashCode = 31 * hashCode + Character.toLowerCase(string.charAt(i));
}
return hashCode;
}
#Override
public boolean equals(String string1, String string2)
{
return string1.equalsIgnoreCase(string2);
}
};
assertThat(
strings.distinct(caseInsensitive),
is(equalTo(Lists.immutable.with("Hello", "world"))));
This could work for Points too, but only if you can group all points within non-overlapping regions to have the same hashcode. If you're using a Comparator defined to return 0 when two Points are close enough, then you can run into transitivity problems. For example, Points A, B, and C can fall along a line with A and C both close to B but far from each other. Still, if this is a useful concept to you, we'd welcome a pull request adding ListIterable.distinct(Comparator) to the API.
Note: I am a committer for Eclipse Collections.

Partial ordered Comparator

How to implement java.util.Comparator that orders its elements according to a partial order relation?
For example given a partial order relation a ≺ c, b ≺ c; the order of a and b is undefined.
Since Comparator requires a total ordering, the implementation orders elements for which the partial ordering is undefined arbitrarily but consistent.
Would the following work?
interface Item {
boolean before(Item other);
}
class ItemPartialOrderComperator implements Comparator<Item> {
#Override
public int compare(Item o1, Item o2) {
if(o1.equals(o2)) { // Comparator returns 0 if and only if o1 and o2 are equal;
return 0;
}
if(o1.before(o2)) {
return -1;
}
if(o2.before(o1)) {
return +1;
}
return o1.hashCode() - o2.hashCode(); // Arbitrary order on hashcode
}
}
Is this comparator's ordering transitive?
(I fear that it is not)
Are Comparators required to be transitive?
(when used in a TreeMap)
How to implement it correctly?
(if the implementation above doesn't work)
(Hashcodes can collide, for simplicity collisions the example ignores collisions; see Damien B's answer to Impose a total ordering on all instances of *any* class in Java for a fail-safe ordering on hashcodes.)
The problem is that, when you have incomparable elements, you need to fall back to something cleverer than comparing hash codes. For example, given a partial order {a < b, c < d}, the hash codes could satisfy h(d) < h(b) < h(c) < h(a), which means that a < b < c < d < a (bold denotes tie broken by hash code), which will cause problems with a TreeMap.
In general, there's probably nothing for you to do except topologically sort the keys beforehand, so some details about the partial orders of interest to you would be welcome.
It seems to be more of an answer than a comment so I'll post it
The documentation says:
It follows immediately from the contract for compare that the quotient is an equivalence relation on S, and that the imposed ordering is a total order on S."
So no, a Comparator requires a total ordering. If you implement this with a partial ordering you're breaching the interface contract.
Even if it might work in some scenario, you should not attempt to solve your problem in a way that breaches the contract of the interface.
See this question about data structures that do fit a partial ordering.
Any time I've tried using hash codes for this sort of thing I've come to regret it. You will be much happier if your ordering is deterministic - for debuggability if nothing else. The following will achieve that, by creating a fresh index for any not previously encountered Item and using those indices for the comparison if all else fails.
Note that the ordering still is not guaranteed to be transitive.
class ItemPartialOrderComperator implements Comparator<Item> {
#Override
public int compare(Item o1, Item o2) {
if(o1.equals(o2)) {
return 0;
}
if(o1.before(o2)) {
return -1;
}
if(o2.before(o1)) {
return +1;
}
return getIndex(o1) - getIndex(o2);
}
private int getIndex(Item i) {
Integer result = indexMap.get(i);
if (result == null) {
indexMap.put(i, result = indexMap.size());
}
return result;
}
private Map<Item,Integer> indexMap = new HashMap<Item, Integer>();
}
In jdk7, your object will throw runtime exception :
Area: API: Utilities
Synopsis: Updated sort behavior for Arrays and Collections may throw an IllegalArgumentException
Description: The sorting algorithm used by java.util.Arrays.sort and (indirectly) by java.util.Collections.sort has been replaced. The
new sort implementation may throw an IllegalArgumentException if it
detects a Comparable that violates the Comparable contract. The
previous implementation silently ignored such a situation.
If the previous behavior is desired, you can use the new system property, java.util.Arrays.useLegacyMergeSort, to restore previous
mergesort behavior.
Nature of Incompatibility: behavioral
RFE: 6804124
If a < b and b < c implies a < c, then you have made a total ordering by using the hashCodes. Take a < d, d < c. The partial order says that b and d not necessarily are ordered. By introducing hashCodes you provide an ordering.
Example: is-a-descendant-of(human, human).
Adam (hash 42) < Moses (hash 17), Adam < Joe (hash 9)
Implies
Adam < Joe < Moses
A negative example would be the same relation, but when time travel allows being your own descendant.
When one item is neither "before" nor "after" another, instead of returning a comparison of the hashcode, just return 0. The result will be "total ordering" and "arbitrary" ordering of coincident items.

Not sure how to sort an ArrayList based on parts of Objects in that ArrayList (Java)

I have a Sorts class that sorts (based on insertion sort, which was the assignment's direction) any ArrayList of any type passed through it, and uses insertion sort to sort the items in the list lexicographically:
public class Sorts
{
public static void sort(ArrayList objects)
{
for (int i=1; i<objects.size(); i++)
{
Comparable key = (Comparable)objects.get(i);
int position = i;
while (position>0 && (((Comparable)objects.get(position)).compareTo(objects.get(position-1)) < 0))
{
objects.set(position, objects.get(position-1));
position--;
}
objects.set(position, key);
}
}
}
In one of my other files, I use a method (that is called in main later) that sorts objects of type Owner, and we have to sort them by last name (if they are the same, then first name):
Directions: "Sort the list of owners by last name from A to Z. If more than one owner have the same last name, compare their first names. This method calls the sort method defined in the Sorts class."
What I thought first was to get the last name of each owner in a for loop, add it to a temporary ArrayList of type string, call Sorts.sort(), and then re-add it back into the ArrayList ownerList:
public void sortOwners() {
ArrayList<String> temp = new ArrayList<String>();
for (int i=0; i<ownerList.size(); i++)
temp.add(((Owner)ownerList.get(i)).getLastName());
Sorts.sort(temp);
for (int i=0; i<temp.size(); i++)
ownerList.get(i).setLastName(temp.get(i));
}
I guess this was the wrong way to approach it, as it is not sorting when I compile.
What I now think I should do is create two ArrayLists (one is firstName, one is LastName) and say that, in a for loop, that if (lastName is the same) then compare firstName, but I'm not sure if I would need two ArrayLists for that, as it seems needlessly complicated.
So what do you think?
Edit: I am adding a version of compareTo(Object other):
public int compareTo(Object other)
{
int result = 0;
if (lastName.compareTo(((Owner)other).getLastName()) < 0)
result = -1;
else if (lastName.compareTo(((Owner)other).getLastName()) > 0)
result = 1;
else if (lastName.equals(((Owner)other).getLastName()))
{
if (firstName.compareTo(((Owner)other).getFirstName()) < 0)
result = -1;
else if (firstName.compareTo(((Owner)other).getFirstName()) > 0)
result = 1;
else if (firstName.equals(((Owner)other).getFirstName()))
result = 0;
}
return result;
}
I think the object should implement a compareTo method that follows the normal Comparable contract--search for sorting on multiple fields. You are correct that having two lists is unnecessary.
If you have control over the Owner code to begin with, then change the code so that it implements Comparable. Its compareTo() method performs the lastName / firstName test described in the assignment. Your sortOwners() method will pass a List<Owner> directly to Sorts.sort().
If you don't have control over Owner, then create a subclass of Owner that implements Comparable. Call it OwnerSortable or the like. It accepts a regular Owner object in its constructor and simply delegates all methods other than compareTo() to the wrapped object. Its compareTo() will function as above. Your sortOwners() method will create a new List<OwnerSortable> out of the Owner list. It can then pass this on to Sorts.sort().
Since you have an ArrayList of objects, ordinarily we would use the Collections.sort() method to accomplish this task. Note the method signature:
public static <T extends Comparable<? super T>> void sort(List<T> list)
What's important here is that all the objects being sorted must implement the Comparable interface, which allows objects to be compared to another in numerical fashion. To clarify, a Comparable object has a method called compareTo with the following signature:
int compareTo(T o)
Now we're getting to the good part. When an object is Comparable, it can be compared numerically to another object. Let's look at a sample call.
String a = "bananas";
String b = "zebras";
System.out.println(a.compareTo(b));
The result will be -24. Semantically, since zebras is farther in the back of the dictionary compared to bananas, we say that bananas is comparatively less than zebras (not as far in the dictionary).
So the solution should be clear now. Use compareTo to compare your objects in such a way that they are sorted alphabetically. Since I've shown you how to compare strings, you should hopefully have a general idea of what needs to be written.
Once you have numerical comparisons, you would use the Collections class to sort your list. But since you have your own sorting ability, not having access to it is no great loss. You can still compare numerically, which was the goal all along! So this should make the necessary steps clearer, now that I have laid them out.
Since this is homework, here's some hints:
Assuming that the aim is to implement a sort algorithm yourself, you will find that it is much easier (and more performant) to extract the list elements into an array, sort the array and then rebuild the list (or create a new one).
If that's not the aim, then look at the Collections class.
Implement a custom Comparator, or change the object class to implement Comparable.

Java: Implement Compararable but too many conditional ifs. How can I avoid them?

I have a list of objects which implement Comparable.
I want to sort this list and that is why I used the Comparable.
Each object has a field, weight that is composed of 3 other member int variables.
The compareTo returns 1 for the object with the most weight.
The most weight is not only if the
weightObj1.member1 > weightObj2.member1
weightObj1.member2 > weightObj2.member2
weightObj1.member3 > weightObj2.member3
but actually is a little more complicated and I end up with code with too many conditional ifs.
If the weightObj1.member1 > weightObj2.member1 holds then I care if weightObj1.member2 > weightObj2.member2.
and vice versa.
else if weightObj1.member2 > weightObj2.member2 holds then I care if weightObj1.member3 > weightObj2.member3 and vice versa.
Finally if weightObj1.member3 > weightObj2.member3 holds AND if a specific condition is met then this weightObj1 wins and vice versa
I was wondering is there a design approach for something like this?
You can try with CompareToBuilder from Apache commons-lang:
public int compareTo(Object o) {
MyClass myClass = (MyClass) o;
return new CompareToBuilder()
.appendSuper(super.compareTo(o)
.append(this.field1, myClass.field1)
.append(this.field2, myClass.field2)
.append(this.field3, myClass.field3)
.toComparison();
}
See also
How write universal comparator which can make sorting through all necessary fields?
Group Comparator, Bean Comparator and Column Comparator
Similar to the above-mentioned Apache CompareToBuilder, but including generics support, Guava provides ComparisonChain:
public int compareTo(Foo that) {
return ComparisonChain.start()
.compare(this.aString, that.aString)
.compare(this.anInt, that.anInt)
.compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
// you can specify comparators
.result();
}
The API for Comparable states:
It is strongly recommended (though not required) that natural
orderings be consistent with equals.
Since the values of interest are int values you should be able to come up with a single value that captures all comparisons and other transformations you need to compare two of your objects. Just update the single value when any of the member values change.
You can try using reflection, iterate over properties and compare them.
You can try something like this:
int c1 = o1.m1 - o2.m1;
if (c1 != 0) {
return c1;
}
int c2 = o1.m2 - o2.m2;
if (c2 != 0) {
return c2;
}
return o1.m3 - o2.m3;
because comparable shall not just return -1, 0 or 1. It can return any integer value and only the sign is considered.

Categories