Question

I am implementing the bubble sort algorithm and I want it to be able to accept both Integer and String parameters. I cast all input as Strings and use the compareTo method to compare the integers casted as strings to the strings. I am getting an incorrect answer when using compareTo to compare the casted integers. What am I doing wrong?

Was it helpful?

Solution

Integer.compareTo sorts numbers numerically. This is what you want.

String.compareTo sorts strings lexicographically; that is, in alphabetical order.

I remember in Windows 3.1 that the folder of photos from my digital camera was ordered like this: PHOTO1, PHOTO10, PHOTO100, PHOTO2, PHOTO20, PHOTO3, ... and so on. Windows XP sorts them more like you would expect: PHOTO1, PHOTO2, PHOTO3, ... etc. This is because it has special sorting rules for strings that represent numbers.

In lexicographical ordering, each character in one string A is compared to the corresponding character in another string B. For each corresponding character in the two strings:

  • If A's current character is lexicographically less than (comes before in the alphabet) B's character, then A comes before B.
  • If B's character is less than A's character, then B comes before A.
  • If the two characters are the same, then we don't know yet. The next one is checked.
  • If there are no more characters left in one of the strings, then the shorter one comes before the longer one.
  • If there are no more character left in both strings, then they are the same string.

The fourth point here is why you are getting incorrect answers, assuming Eddie's analysis of your problem is correct.

Consider the strings "10" and "2". Lexicographical ordering would look at the first characters of each, '1' and '2' respectively. The character '1' comes before '2' in the character set that Java uses, so it sorts "10" before "2", in the same way that "bare" is sorted before "hare" because 'b' comes before 'h'.

I suggest you cast your strings to integers before sorting. Use Integer.parseString to do this.

OTHER TIPS

are you sure you want to mix Integers and Strings in the same list? if so, are Integers less or greater than Strings? what is this particular sorting criteria?

you can also make a bubble sort method which sorts distinct lists of Integer and lists of String (and lists of any other class). to do so, you can use Generics. for example:

public static <T> void bubbleSort(List<T> elements, Comparator<T> comparator) {
    // your implementation
}

you use the comparator parameter to compare the elements, that's why they can be Integers or Strings (not both at the same time). the compiler won't let you [without any warning] pass a list of objects of one class and a comparator of a different class, so the comparison will always work.

Take an instance of Comparable.

Strings can't really be cast to integers, and there is no comparryo method.

What you describe isn't really possible... so perhaps you need to post the code. Here is my interpretation of wht you are doing:

public int compareTo(final Object o)
{
    final String str;

    str = (String)o; // this will crash if you pass it an Integer.

    // rest of the code.
}

The documentation for compareTo is here, you really should follow the contract.

Firstly you want Comparator not Comparable because Comparator takes two objects whereas Comparable compares the current object to one passed in and you can't change the compareTo() method on String or Integer so:

public class CompareIntegersAsStrings implements Comparator {
  public int compare(Object o1, Object o2) {
    return o1.toString().compareTo(o2.toString());
  }
}

Assuming that what you really mean is that you are converting Integers to Strings, and then comparing, this will not work. For example, let's say you have the Integer 1234 and the Integer 1 and the Integer 2. If you convert these to Strings and compare them, you will get the order:

1
1234
2

which is correct for ASCII sorting and incorrect for numeric sorting. That is, I assume your code does something like this:

public int myCompare(Integer a1, Integer a2) {
    myCompare(String.valueOf(a1), String.valueOf(a2));
}

public int myCompare(String a1, String a2) {
    ....
}

Why do I assume this? Because you are talking about getting an incorrect result and not talking about getting Exceptions. If you are actually getting Exceptions, then the other posters are correct that casting will not work.

It is because of the below java API code in String class where minimum length of chars among the two string are only compared.

public int compareTo(String anotherString) {
    int len1 = value.length;
    int len2 = anotherString.value.length;
    int lim = Math.min(len1, len2); //**HERE**
    char v1[] = value;
    char v2[] = anotherString.value;

    int k = 0;
    while (k < lim) {
        char c1 = v1[k];
        char c2 = v2[k];
        if (c1 != c2) {
            return c1 - c2;
        }
        k++;
    }
    return len1 - len2;
}

If we use this api to compare

String first = "ABCD"; 
String second = "ABZ"; 
System.out.println("" + "ABCD".compareTo("ABZ")); //-23

will return negative value saying ABCD is less than ABZ means C is less than Z and ignored D in the first String.

So maybe we need something like below

class StringNumericComparator implements Comparator<String> {
    @Override
    public int compare(String o1, String o2) {
        int len1 = o1.length();
        int len2 = o2.length();
        if(len1 != len2) {
            return len1 - len2; //Else iterate all diff lengh chars and SUM it.
        }
        int lim = Math.min(len1, len2);
        char v1[] = o1.toCharArray();
        char v2[] = o2.toCharArray();

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return 0;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top