问题
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?
回答1:
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.
回答2:
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.
回答3:
Take an instance of Comparable
.
Strings can't really be cast to integers, and there is no comparryo method.
回答4:
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.
回答5:
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());
}
}
回答6:
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.
回答7:
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;
}
}
来源:https://stackoverflow.com/questions/900745/java-compareto-for-string-and-integer-arguments