Thursday 1 August 2013

Custom sorting!!

Hi All,
First of all I would like to share my two posts in separate blogs :

Imutable classes : http://nitskkjavabitsmutableclasses.blogspot.in/ 
and
Generics :             http://nitskkjavabits.blogspot.in/ 

Yesterday I was asked a question about sorting an array of numbers , where numbers are in form of  "one","two","three"... 

Well Java is great with lot of ready-made stuff, but in the end it is a tool. Our JVM possess great power but lacks one thing which almighty have blessed us all with and that is our Mind and its massive abilities. As a java programmer we need to give logic as per our requirement and then ask the JVM to process our logic and give results.

So if we have few Strings, or our Custom Objects , and we want those objects to get sorted as per our requirement then  the onus is upon the  programmer to provide the business requirement  to the program and then rely on the 'Java ready made sorting algorithm' to sort.

In the question asked to me , there were simple Strings, but it could have been some Custom Java objects also. For simplicity and better understanding I am sharing below two Programs solving the sorting of numbers stored as strings "one", "two", "three"... Program one helps in developing the logic and program two is more generic and flexible. 

Program 1:


import java.util.Arrays;
import java.util.Comparator;

public class ArraySorting {
public static void main(String[] args) {
String[] numbers = { "three", "one", "four", "two" };
System.out.println("**** sorting straight****");
StraightComparator straightComparator = new StraightComparator();
Arrays.sort(numbers, straightComparator);
for (String s : numbers) {
System.out.println(s);
}
System.out.println("***sorting reverse****");
ReverseComparator reverseComparator = new ReverseComparator();
Arrays.sort(numbers, reverseComparator);
for (String s : numbers) {
System.out.println(s);
}
}

static private class StraightComparator implements Comparator<String> {

/**
* Returns: a negative integer, zero, or a positive integer as the first
* argument is less than, equal to, or greater than the second.
*/
@Override
public int compare(String o1, String o2) {
int retValue = 0;

// equal case
if (o1.equalsIgnoreCase(o2)) {
retValue = 0;
} else // o1 is "one" and o2 is not "one" always return -ve
if (o1.equalsIgnoreCase("one")) {
retValue = -1;
} else // o1 is "four" and o2 is not "four" always return +ve
if (o1.equalsIgnoreCase("four")) {
retValue = 1;
} else // o2 is "one" and o1 is not "one" always return +ve
if (o2.equalsIgnoreCase("one")) {
return 1;
} else // o2 is "four" and o1 is not "four" always return -ve
if (o2.equalsIgnoreCase("four")) {
return -1;
} else // o1 is "two" and o2 is not "two", not "one", not "four",
// means o2 is "three" always return +ve
if (o1.equalsIgnoreCase("two")) {
return -1;
} else // o1 is "three" and o2 is not "three", not "one", not
// "four", means o2 is "two" always return +ve
if (o1.equalsIgnoreCase("three")) {
return 1;
}
return retValue;
}
}

static private class ReverseComparator implements Comparator<String> {

@Override
public int compare(String o1, String o2) {
StraightComparator straightComparator = new StraightComparator();
return straightComparator.compare(o2, o1);
}

}
}

Program 2:  This is based on the same logic as developed in above program. This do not have the reverse Comparator, as its logic shall remain the same as above. This programs is more flexible and  involves proper use of custom exception for illegal input. 



import java.util.Arrays;
import java.util.Comparator;

public class CustomStringNumberSorter implements Comparator<String> {
private int minIndex = -1;
private int maxIndex = -1;
private final String[] numbersAvailable = { "one", "two", "three", "four",
"five", "six", "seven", "eight", "nine", "ten" };
private String[] numbersToSort;

private CustomStringNumberSorter(String[] numbersToSort) {
this.numbersToSort = numbersToSort;
setMinIndex();
setMaxIndex();
}

private void checkInputArray() throws IllegalInputException {
boolean isInputCorrect = false;
if (numbersToSort == null) {
isInputCorrect = false;
} else {
for (String stringToSort : numbersToSort) {
int i = 0;
for (i = 0; i < numbersAvailable.length; i++) {
if (stringToSort.equalsIgnoreCase(numbersAvailable[i])) {
isInputCorrect = true;
break; //breaking  inner loop
}
}
if (i == numbersAvailable.length) {
isInputCorrect = false;
break; //breaking the outer loop
}
}
}
if (!isInputCorrect) {
throw new IllegalInputException();
}
}

public static void sort(String[] numbersToSort)
throws IllegalInputException {
CustomStringNumberSorter customStringNumberSorter = new CustomStringNumberSorter(
numbersToSort);
customStringNumberSorter.checkInputArray();
Arrays.sort(numbersToSort, customStringNumberSorter);
}

private void setMinIndex() {
// there is a scope for writing a better logic to this method but lets
// continue with below for now
for (String numberToSort : numbersToSort) {
int index = 0;
for (String availableNumber : numbersAvailable) {
if (numberToSort.equalsIgnoreCase(availableNumber)) {
if (minIndex == -1 || index < minIndex) {
minIndex = index;
}
break;
}
index++;
}
}
}

private void setMaxIndex() {
// there is a scope for writing a better logic to this method but lets
// continue with below for now
for (String numberToSort : numbersToSort) {
int index = 0;
for (String availableNumber : numbersAvailable) {
if (numberToSort.equalsIgnoreCase(availableNumber)) {
if (maxIndex == -1 || index > maxIndex) {
maxIndex = index;
}
break;
}
index++;
}
}
}

@Override
public int compare(String o1, String o2) {
int retValue = 0;
if (o1.equalsIgnoreCase(o2)) {
retValue = 0;
} else {
for (int i = minIndex; i <= maxIndex; i++) {
if (o1.equalsIgnoreCase(numbersAvailable[i])) {
retValue = -1;
break;
} else if (o2.equalsIgnoreCase(numbersAvailable[i])) {
retValue = 1;
break;
}
}
}
return retValue;
}

public static class IllegalInputException extends Exception {
public IllegalInputException() {
super(
"The input contains an element which is not contained in the available numbers!!");
}
}

/**
* TESTING THE LOGIC WRITTEN
* @param args
*/
public static void main(String[] args) {
String[] numbers = { "two", "five", "nine", "eight", "one" };
try {
CustomStringNumberSorter.sort(numbers);
for (String number : numbers) {
System.out.println(number);
}
} catch (IllegalInputException e) {
System.out.println("Exception Occured :" + e.getMessage());
}

}
}

The program two can be used for sorting the custom Objects as well, The custom Class needs to implement the equals method and with only few modifications in program two custom Objects can also be sorted. Shall be sharing the program to sort the custom java objects soon...

Thanks for giving time and reading the blog...