Why is compareTo() behaving like this - java

I am trying to compare two strings. I am using the compareTo method but am seeing some behavior I don't understand.
System.out.println("5".compareTo("10") > 0);
System.out.println("13".compareTo("10") > 0);
Why do both of these statements output true?

The natural ordering for Java strings is lexicographical, not numerical. (See the javadoc for what lexicographical means in the context of a Java string.)
For the first example, the character '5' is greater than the character '1', so "5" is larger than "10".
For the second example, the '1' is common to both strings. So we move on to the 2nd characters, and compare '3' with '0'. The former is larger, so "13" is larger than "10".
And:
Why is compareTo() behaving like this
Because the spec says it should; see link above. And because it makes sense.
(You would not want the String::compareTo() method to try to distinguish between words and numbers and order words alphabetically and numbers numerically ... and scratch its metaphorical head over strings that are neither one or the other!)

When you provide value in ("") it is treated as String and String comparision is different then number comparision.
try below and you will know.
Integer targetValue = 10;
Integer firstValue = 5;
Integer secondValue = 13;
System.out.println("5".compareTo("10") > 0);
System.out.println("13".compareTo("10") > 0);
System.out.println(firstValue.compareTo(targetValue) > 0);
System.out.println(secondValue.compareTo(targetValue) > 0);

Related

How to convert int value 09 to char array as {'0','9'}?

I am working on the problem to find the next greatest number with the same set of digits.
For this I take a integer value input from the user and I want to convert to char array or int array so that I can access individual digits.
But when I take
int value=09 as the input and convert to char array it gives only 9 as it considers it to be octal value. How can I overcome this ?
it is not possible in java to take the int values with leading zeros.
so for the value with leading zeros take it in string format.
but we can insert zeros
int n=7;
String str=String.format("%04d", n); //4 denotes the size of the string
System.out.println(str); // o/p->0007
It is not possible convert a 09 int value to a String of 9 since the value 09 can not be stored in an int.
int is not capable of storing trailing zeros.
Take this sample.
int foo = Integer.valueOf("09");
System.out.println(foo);
Output
9
So to solve your problem you should get a String from the user, validate it and parse it to an Integer[].
Solution
public Integer[] parseToInteger(String number) {
return Arrays.asList(number.toCharArray())
.stream()
.map(c -> Integer.valueOf(c.toString()))
.toArray(size -> new Integer[size]);
}
Now you have an Array of Integer.
Since leading 0's are dropped from integers there is no reason to support assigning such a value to an int.
If I want to convert 9 to '9' I usually just add '0' to it.
You can also do the following:
char c = Character.forDigit(9,10);
If you have a string of characters, you can do the following:
String str = "09";
List<Character> chrs =
str.chars().mapToObj(a -> Character.valueOf((char) a))
.collect(Collectors.toList());
System.out.println(chrs);
Prints
[0,9]
You are asking how to parse a number starting with a leading zero, but I get the feeling that you are actually on the worng track given the problem you are trying to resolve. So let's take one step backward, and lets make sure I understand your problem correctly.
You say that you have to find the "next greatest number with the same set of digits". So you are playing "Scrabble" with digits, trying to find the smalest number composed with the same digits that is strictly greater to the original number. For example, given the input "09", you would output "90", and for "123", you would output "132". Is that right? Let assume so.
Now, the real challenge here is how to determine the smalest number composed with thise digits that is stricly greater to the original number. Actually, there's a few possible strategies:
Enumerate all possible permutations of those digits, then filter out those that are not strictly greater to the original number, and then, among the remaining values, find the smallest value. That would be a very innefficient strategy, requiring both disproportionate memory and processing power. Please, don't consider this seriously (that is, unless you are actually coding for a Quantum Computer ;) ).
Set a variable to the initial number, then iteratively increment that variable by one until you eventually get a number that is composed of the same digits as the original values. That one might look simple to implement, but it actually hides some complexities (i.e. determining that two numbers are composed from the same digits is not trivial, special handling would be required to avoid endless loop if the initial number is actually the greatest value that can be formed with those digits). Anyway, this strategy would also be rather innefficient, requiring considerable processing power.
Iterate over the digits themselves, and determine exactly which digits have to be swapped/reordered to get the next number. This is actually very simple to implement (I just wrote it in less that 5 minutes), but require some thinking first. The algorithm is O(n log n), where n is the length of the number (in digits). Take a sheet of paper, write example numbers in columns, and try to understand the logic behind it. This is definitely the way to go.
All three strategies have one thing in common: they all require that you work (at some point at least) with digits rather than with the number itself. In the last strategy, you actually never need the actual value itself. You are simply playing Scrabble, with digits rather than letters.
So assuming you indeed want to implement strategy 3, here is what your main method might looks like (I wont expand more on this one, comments should be far enough):
public static void main(String[] args) {
// Read input number and parse it into an array of digit
String inputText = readLineFromUser();
int[] inputDigits = parseToDigits(inputText);
// Determine the next greater number
int[] outputDigits = findNextGreaterNumber(inputDigits);
// Output the resulting value
String outputText = joinDigits(outputDigits);
println(outputText);
}
So here's the point of all this discussion: the parseToDigits method takes a String and return an array of digits (I used int here to keep things simpler, but byte would actually have been enough). So basically, you want to take the characters of the input string, and convert that array to an array of integer, with each position in the output containing the value of the corresponding digit in the input. This can be written in various ways in Java, but I think the most simple would be with a simple for loop:
public static int[] parseToDigits(String input) {
char[] chars = input.toCharArray();
int[] digits = new int[chars.length];
for (int i = 0 ; i < chars.length ; i++)
digits[i] = Character.forDigit(chars[i], 10);
return digits;
}
Note that Character.forDigit(digit, radix) returns the value of character digit in base radix; if digit is not valid for the given base, forDigit returns 0. For simplicity, I'm skipping proper validation checking here. One could consider calling Character.isDigit(digit, radix) first to determine if a digit is acceptable, throwing an exception if it is not.
As to the opposite opperation, joinDigits, it would looks like:
public static String joinDigits(int[] digits) {
char[] chars = new char[digits.length];
for (int i = 0 ; i < digits.length ; i++)
chars[i] = Character.digit(digits[i], 10);
return new String(chars);
}
Hope that helps.

How can I zero-pad a hexadecimal digit string to eight digits?

I have a logic requirement, where I need to ensure that a hexadecimal digit string is presented in 8-digit format, even if the leading digits are zero. For example, the string corresponding to 0x3132 should be formatted as "0x00003132".
I tried this:
String key_ip = txt_key.getText();
int addhex = 0;
char [] ch = key_ip.toCharArray ();
StringBuilder builder = new StringBuilder();
for (char c : ch) {
int z = (int) c;
builder.append(Integer.toHexString(z).toUpperCase());
}
System.out.println("\ n (key) is:" + key_ip);
System.out.println("\ nkey in Hex:" + addhex + builder.toString());
, but it gave me an error. Can anyone explain how to fix or rewrite my code for this?
and I want to ask one more thing, if use code
Long.toHexString(blabla);
is it true to change the value "0x00" to "\0030" so that the output of 0 is 30
Evidently, you are receiving a String, converting its chars to their Unicode code values, and forming a String containing the hexadecimal representations of those code values. The problem you want to solve is to left-pad the result with '0' characters so that the total length is not less than eight. In effect, the only parts of the example code that are directly related to the problem itself are
int addhex = 0;
and
System.out.println("\ nkey in Hex:" + addhex + builder.toString());
. Everything else is just setup.
It should be clear, however, that that particular attempt cannot work, because all other considerations aside, you need something that adapts to the un-padded length of the digit string. That computation has no dependency on the length of the digit string at all.
Since you're already accumulating the digit string in a StringBuilder, it seems sensible to apply the needed changes to it, before reading out the result. There are several ways you could approach that, but a pretty simple one would be to just insert() zeroes one at a time until you reach the wanted length:
while (builder.length() < 8) {
builder.insert(0, '0'); // Inserts char '0' at position 0
}
I do suspect, however, that you may have interpreted the problem wrongly. The result you obtain from doing what you ask is ambiguous: in most cases where such padding is necessary, there are several input strings that could produce the same output. I am therefore inclined to guess that what is actually wanted is to pad the digits corresponding to each input character on a per-character basis, so that an input of "12" would yield the result "00310032". This would be motivated by the fact that Java char values are 16 bits wide, and it would produce a transformation that is reliably reversible. If that's what you really want, then you should be able to adapt the approach I've presented to achieve it (though in that case there are easier ways).
if use code
Long.toHexString(blabla);
is it true to change the value "0x00" to "\0030" so that the output of
0 is 30
The Unicode code value for the character '0', expressed in hexadecimal, is 30. Your method of conversion would produce that for the input string "0". Your method does not lend any special significance to the character '\' in its input.

What does compareTo() actually return?

The compareTo() method in Java returns a value greater/equal/less than 0 and i know that. However, the value itself is my question. What is the difference between 2 or 4 when compareTo() returns. Look at the code below
String s1="hello";
String s2="hello";
String s3="meklo";
String s4="hemlo";
System.out.println(s1.compareTo(s2)); // 0
System.out.println(s1.compareTo(s3)); // -5
System.out.println(s1.compareTo(s4)); // -1
Why the last two commands are -5 and -1?
https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#compareTo(java.lang.String)
This is the definition of lexicographic ordering. If two strings are different, then either they have different characters at some index that is a valid index for both strings, or their lengths are different, or both. If they have different characters at one or more index positions, let k be the smallest such index; then the string whose character at position k has the smaller value, as determined by using the < operator, lexicographically precedes the other string. In this case, compareTo returns the difference of the two character values at position k in the two string -- that is, the value:
this.charAt(k)-anotherString.charAt(k)
If there is no index position at which they differ, then the shorter string lexicographically precedes the longer string. In this case, compareTo returns the difference of the lengths of the strings -- that is, the value:
this.length()-anotherString.length()
compareTo() returns the difference of first unmatched character in the two compared strings. If no unmatch is found, and one string comes out as shorter than other one, then the length difference is returned.
"hello".compareTo("meklo") = 'h' - 'm' = -5
^ ^
and
"hello".compareTo("hemlo") = 'l' - 'm' = -1
^ ^
As a side note:
Non-zero values are mostly considered as true inside conditional statements. So, compareTo can simply return these non-zero values instead of processing them into 1(small optimisation).
If you take closer look at the source code for String#compareTo(String), you can see that the exact results are ambiguous.
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
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;
}
In most cases (i.e. a difference in the characters of both strings) it will return the integer difference of the char values of the first differing characters. Otherwise it will return the difference of the lengths of both strings.
The interpretation of the return value beyond = 0, > 0 and < 0 should be of no concern in practice, since the implementation is allowed to change at any time if the contract of Comparable<T>#compareTo(T) is kept:
Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
Source: https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html#compareTo-T-
The exact value does not matter - all that the Comparable (as well as Comparator) interface cares about is whether the value is negative, zero or positive.
This is to make things simple for implementations of the interface. When implementing it, you may choose to return the basic -1, 0 or 1 (this is usual if the comparison relies on evaluating some conditions), or you may use any arbitrary negative or positive value if it suits you better - e.g. you can compare two integers by returning this.i - other.i.
In your particular given example, my guess would be:
-1 is difference in the third letter's code point: 'l' - 'm' == -1
-5 is difference in the first letter's code point: 'h' - 'm' == -5
But the important part is that you shall not rely on it to be that way - it's an implementation detail, and according to Comparable's contract any negative value shall be treated the same ("less than").

What does the String classes compareTo() method return

In the Java API on oracles website: "compareTo Returns: "the value 0 if the argument string is equal to this string; a value less than 0 if this string is lexicographically less than the string argument; and a value greater than 0 if this string is lexicographically greater than the string argument." "
Here is an if statement:
String a = "abd";
String b = "abc";
if(a.compareTo(b) >= 1)
returns true
since string a is greater, lexicographically.
My question is, does the compareTo always return a 0, 1, or -1? or does it return the actual amount that the string is greater than or less than the string argument.
So in the above if statement, since "abd" is one greater than "abc" is it returning 1?
As far as you're concerned, there's no telling what the magnitude of the compareTo return value is, just the sign. In practice, most compareTo implementations will return -1, 0, or 1, but the contract specifically says positive or negative, and you should write your code accordingly (e.g., using int compare = a.compareTo(b); if(compare > 0) {...} else...).
According to http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#compareTo%28java.lang.String%29
In this case, compareTo returns the difference of the two character values at position k >in the two string -- that is, the value:
this.charAt(k)-anotherString.charAt(k)
If there is no index position at which they differ, then the shorter string lexicographically precedes the longer string. In this case, compareTo returns the difference of the lengths of the strings -- that is, the value:
this.length()-anotherString.length()
For the last case, for the lengths of the String, by documentation that seems it can return other than -1, 0, 1
Falmarri fully answered this question; as opposed to only indicating the conditions in which the return value would be positive, negative or zero.
"This is the definition of lexicographic ordering. If two strings are different, then either they have different characters at some index that is a valid index for both strings, or their lengths are different, or both. If they have different characters at one or more index positions, let k be the smallest such index; then the string whose character at position k has the smaller value, as determined by using the < operator, lexicographically precedes the other string. In this case, compareTo returns the difference of the two character values at position k in the two string -- that is, the value:
this.charAt(k)-anotherString.charAt(k)
If there is no index position at which they differ, then the shorter string lexicographically precedes the longer string. In this case, compareTo returns the difference of the lengths of the strings -- that is, the value:
this.length()-anotherString.length()"

java comparing integers as strings with a comparator - odd results

I'm attemping to compare some players with a comparator by the amount of runs they have obtained.
System.out.println("Comparing: " + p2.getRuns() + " and " + p1.getRuns());
int newRESULT = intConvert(p2.getRuns()).compareTo(intConvert(p1.getRuns()));
System.out.println("Returns: " + newRESULT);
return newRESULT;
However this returns:
Comparing: 25 and 0,
Returns: 2
Comparing: 0 and 100,
Returns: -1
Comparing: 25 and 100,
Returns: 1
...and hence orders the players in the wrong order.
Should the first comparison not return 1, the second -1 and the last -1 as well?
intConvert:
private static String intConvert(int x)
{
return "" + x;
}
I assume intConvert(...) converts an int to a String, and thus you get lexical comparisons which meahs "25" is greater than "100" because the first character is greater (2 > 1).
If you want to get correct comparisons stick to comparing ints or if you need to use a String create strings of equal length and fill in missings zeros at the front (e.g. 25 -> "025").
To compare Numbers that are represented as String in a sensible way, you need to consistently format them all the same way.
Strings use lexical comparisons. This means "5" will be > "20" because 5 is > than 2. To get the logically expected output you need to format the numbers with some kind of formatter to make them lexically comparable.
"05" is < "20"
The simplest thing would be to use String.format() and a pattern to format all the numbers to Strings so they will compare consistently lexically.
String.format("%04d", yourInteger);
This will produce all ints that are passed in as left padded with 0 for 4 positions.
String.format("%04d", 5);
will produce 0005
Make the "%0Xd" where X is the number of digits you want it formatted to.
You don't have to convert the numbers to strings just to sort, you can do something like:
class ComparePlayersByRuns implements Comparator<Player> {
public int compareTo(Player p1, Player p2) {
return p1.getRuns().compareTo(p2.getRuns());
}
}
or in Java 8 and later all you need to create your comparator is:
Comparators.comparing(Player::getRuns);
And no, the compare isn't required to return 1, 0, or -1, the documentation says:
Returns:
a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

Categories