I'm trying to see how to manually calculate the output when comparing strings as questions like it have come up in past papers I'm practicing.
I understand that the result is negative if the string lexicographically (according to unicode) precedes the argument string, positive if it follows it and zero if they are equal. I don't see how to calculate the value (beyond the sign).
I have the code which gives the output 1, -1, -3, 3. I see why each is positive or negative but not why it is 1 or 3.
public class CompareToPractice {
public static void main(String[] args) {
String str1 = "bode";
String str2 = "bod";
String str3 = "bodge";
String str4 = "bog";
int result1 = str1.compareTo(str2);
System.out.println(result1);
int result2 = str2.compareTo(str1);
System.out.println(result2);
int result3 = str3.compareTo(str4);
System.out.println(result3);
int result4 = str4.compareTo(str3);
System.out.println(result4);
}
}
Thank you
Its the difference between the characters 'd' and 'e' (ascii difference).
This is the code of compareTo
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;
}
As you can see from line if (c1 != c2). If 2 characters are not equal, then the result will be the subtraction of those 2 values.
In your case str3.compareTo(str4) was "bodge" - "bog".
So 'd'-'g' (ASCII value: 100 - 103 = -3)
I don't see how to calculate the value (beyond the sign).
The value "beyond the sign" is irrelevant. It conveys no information that a normal application could make use of1. It is a mere implementation detail: an accidental artifact of an algorithm that is optimized for speed.
If you really want to know, look at the source code.
1 - Well I suppose you could in theory construct a program that used it. But I can't conceive of a problem that such a program would solve ... apart from circular problems, such as investigating the statistical properties of compareTo!
The documentation of compareTo clearly defines in what cases the result is calculated and how.
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()
Also Bandi Kishore's answer explains the ASCII difference calculation: https://stackoverflow.com/a/36858565/904375
Related
So I'm stuck on this problem, where you have a method equalNumbers(String str, int num), that determines whether characters in str represent the same number as num. The empty string is equivalent to zero.
equalNumbers("123", 123) true
equalNumbers("9", 999) false
And so on.
This method is supposed to be recursive, so no loops, and no using stuff like Integer.parseInt, Integer.valueOf, and integer.decode(). Helper functions are allowed.
It encourages the use of charAt(index) and Character.gerNumericValue(ch).
===
Based on what it encourages me to do, I suppose it wants me to iterate through the string char by char, convert that char to an integer, and compare it to one digit in the integer at a time. It seems the only conversion I am allowed to do is char to int. So my questions are:
Should I build a string out of the chars and then convert that whole string into an integer? (Don't think that's allowed)
Is it possible to go index by index in an integer, without converting it into a string?
I would show my own code, but I have a conceptual gap about how these data types work.
Often a public function calls a private recursive function with an extra parameter.
For your code using get_int_at_index the extra recursive function would need i to be passed.
In your case this is not needed, but then you need to work with String (inspecting a tiny part with charAt) and int. Now I suspect String.valueOf(int) was not intended, but inspecting a tiny part of the number, a digit, by number modulo 10 (% 10).
Taking modulo ten would give the rightmost digit first, so:
int num
int digit = num % 10; // Tiny part we deal with
num = num / 10; // Rest
String str
char ch = str.charAt(str.length() - 1); // Tiny part
str = str.substring(0, str.length() - 1); // Rest
So
public static boolean equalNumbers(String str, int num) {
if (str.isEmpty()) { // End recursion.
return num == 0;
}
char ch = str.charAt(str.length() - 1);
int digit = num % 10;
if (Character.getNumericValue(ch) != digit) {
return false;
}
str = str.substring(0, str.length() - 1);
num = num / 10;
return equalNumbers(str, num); // Recurse.
}
Compareto don't give me -10 for bigger argument. (when the string is equal with argument then i get 0).
String str2 = "Strings are immutable";
String str3 = "Int is a";
int result = str3.compareTo( str2 );
System.out.println(result);
result = str2.compareTo( str3 );
System.out.println(result);
if you change the size of str2 or str3 the return number is the same. why is that?
The only thing you can rely on when comparing Strings with compareTo is that the output would be < 0 if the String on which you call the method comes before the other String (according to lexicographical order), > 0 if it comes after the other String, and 0 if they are equal.
From the Javadoc:
int java.lang.String.compareTo(String anotherString)
Compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings. The character sequence represented by this String object is compared lexicographically to the character sequence represented by the argument string. The result is a negative integer if this String object lexicographically precedes the argument string. The result is a positive integer if this String object lexicographically follows the argument string. The result is zero if the strings are equal; compareTo returns 0 exactly when the equals(Object) method would return true.
You shouldn't make any assumptions regarding the actual value returned by that method, since that's an implementation detail, that can change in any future version of Java.
The Java 8 implementation happens to return c1 - c2 where c1 and c2 are the first pair of corresponding characters of the compared Strings not equal to each other. The lengths of the compared Strings only affect the returned value if one String is a sub-string of the other.
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 your example the compared Strings differ in their first character, so str2.compareTo(str3) will return str2.charAt(0)-str3.charAt(0), and str3.compareTo(str2) will return str3.charAt(0)-str2.charAt(0).
First off, you shouldn't try to interpret the return value from compareTo in any other way than negative, zero, positive. The greatness of the value returned carries no meaning.
That said, String.compareTo in OpenJDK looks like this:
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;
}
Since strings compare in alphabetical order the length of the strings doesn't matter - a string beginning with I will come before a string beginning with S regardless of how long they are.
In case of strings we compare each character in the string with the character in the same place in the other string alphabetically and to do this in Java we can use a simple trick.
In Java we can perform arithmetics on chars and to do this we need to understand how characters are really represented. You see the character I but the computer sees the code point 73 - for S the code point is 83. When String.compareTo sees that S and I aren't the same character it returns S - I which in code-point arithmetic is 83 - 73 and that's why you get 10 (or -10 if you switch the order of the strings.
Can someone please explain to me what is going on here:
char c = '+';
int i = (int)c;
System.out.println("i: " + i + " ch: " + Character.getNumericValue(c));
This prints i: 43 ch:-1. Does that mean I have to rely on primitive conversions to convert char to int? So how can I convert a Character to Integer?
Edit: Yes I know Character.getNumericValue returns -1 if it is not a numeric value and that makes sense to me. The question is: why does doing primitive conversions return 43?
Edit2: 43 is the ASCII for +, but I would expect the cast to not succeed just like getNumericValue did not succeed. Otherwise that means there are two semantic equivalent ways to perform the same operation but with different results?
Character.getNumericValue(c)
The java.lang.Character.getNumericValue(char ch) returns the int value that the specified Unicode character represents. For example, the character '\u216C' (the roman numeral fifty) will return an int with a value of 50.
The letters A-Z in their uppercase ('\u0041' through '\u005A'), lowercase ('\u0061' through '\u007A'), and full width variant ('\uFF21' through '\uFF3A' and '\uFF41' through '\uFF5A') forms have numeric values from 10 through 35. This is independent of the Unicode specification, which does not assign numeric values to these char values.
This method returns the numeric value of the character, as a
nonnegative int value;
-2 if the character has a numeric value that is not a nonnegative integer;
-1 if the character has no numeric value.
And here is the link.
As the documentation clearly states, Character.getNumericValue() returns the character's value as a digit.
It returns -1 if the character is not a digit.
If you want to get the numeric Unicode code point of a boxed Character object, you'll need to unbox it first:
int value = (int)c.charValue();
Try any one of the below. These should work:
int a = Character.getNumericValue('3');
int a = Integer.parseInt(String.valueOf('3');
From the Javadoc for Character#getNumericValue:
If the character does not have a numeric value, then -1 is returned.
If the character has a numeric value that cannot be represented as a
nonnegative integer (for example, a fractional value), then -2 is
returned.
The character + does not have a numeric value, so you're getting -1.
Update:
The reason that primitive conversion is giving you 43 is that the the character '+' is encoded as the integer 43.
43 is the dec ascii number for the "+" symbol. That explains why you get a 43 back.
http://en.wikipedia.org/wiki/ASCII
public class IntergerParser {
public static void main(String[] args){
String number = "+123123";
System.out.println(parseInt(number));
}
private static int parseInt(String number){
char[] numChar = number.toCharArray();
int intValue = 0;
int decimal = 1;
for(int index = numChar.length ; index > 0 ; index --){
if(index == 1 ){
if(numChar[index - 1] == '-'){
return intValue * -1;
} else if(numChar[index - 1] == '+'){
return intValue;
}
}
intValue = intValue + (((int)numChar[index-1] - 48) * (decimal));
System.out.println((int)numChar[index-1] - 48+ " " + (decimal));
decimal = decimal * 10;
}
return intValue;
}
char c = '0';
int i = 0;
System.out.println(c == i);
Why does this always returns false?
Although this question is very unclear, I am pretty sure the poster wants to know why this prints false:
char c = '0';
int i = 0;
System.out.println(c == i);
The answer is because every printable character is assigned a unique code number, and that's the value that a char has when treated as an int. The code number for the character 0 is decimal 48, and obviously 48 is not equal to 0.
Why aren't the character codes for the digits equal to the digits themselves? Mostly because the first few codes, especially 0, are too special to be used for such a mundane purpose.
The char c = '0' has the ascii code 48. This number is compared to s, not '0'. If you want to compare c with s you can either do:
if(c == s) // compare ascii code of c with s
This will be true if c = '0' and s = 48.
or
if(c == s + '0') // compare the digit represented by c
// with the digit represented by s
This will be true if c = '0' and s = 0.
The char and int value can not we directly compare we need to apply casting. So need to casting char to string and after string will pars into integer
char c='0';
int i=0;
Answer is like
String c = String.valueOf(c);
System.out.println(Integer.parseInt(c) == i)
It will return true;
Hope it will help you
Thanks
You're saying that s is an Integer and c (from what I see) is a Char.. so there you, that's the problem: Integer vs. Char comparation.
Output for converting a number in decimal into its 1s complement and then again converting the number into decimal does not come as expected.
MyApproach
I first converted the number from decimal to binary. Replaced all Os with 1 and vice versa and then converted the number into decimal.
Can anyone guide me? What I am doing wrong?
Code:
public static int complimentDecimal(int num) {
int p = 0;
String s1 = "";
// Convert Decimal to Binary
while (num > 0) {
p = num % 2;
s1 = p + s1;
num = num / 2;
}
System.out.println(s1);
// Replace the 0s with 1s and 1s with 0s
for (int j = 0; j < s1.length(); j++) {
if (s1.charAt(j) == 0) {
s1.replace(s1.charAt(j), '1');
} else {
s1.replace(s1.charAt(j), '0');
}
}
System.out.println(s1);
int decimal = 0;
int k = 0;
for (int m = s1.length() - 1; m >= 0; m--) {
decimal += (s1.charAt(m) * Math.pow(2, k));
k++;
}
return decimal;
}
First of all you need to define the amount of Bits your binary representation should have or an complement representation does not make sense.
If you convert 100 the binary is 1100100
complement is 0011011 which is 27
now convert 27. Binary is 11011, complement 00100 which is 4.
Now define yourself a Bit length of 8.
100 is 01100100, complement 10011011, is 155
155 is 10011011, complement 01100100, is 100
Works because every binary representation has a length of 8 bits. This is absolutly necessary for the whole complement thing to make any sense.
Consider that you now have a limit for numbers that are convertable.
11111111 which is 255.
Now that we talked about that I will correct your code
static int MAX_BITS = 8;
static int MAX_INT = (int)Math.pow(2, MAX_BITS) - 1;
public static int complimentDecimal(int num)
{
// check if number is to high for the bitmask
if(num > MAX_INT){
System.out.println("Number=" + num + " to high for MAX_BITS="+MAX_BITS);
return -1;
}
// Your conversion works!
int p=0;
String s1="";
//Convert Decimal to Binary
while(num>0)
{
p=num%2;
s1=p+s1;
num=num/2;
}
// fill starting zeros to match MAX_BITS length
while(s1.length() < MAX_BITS)
s1 = "0" + s1;
System.out.println(s1);
//Replace the 0s with 1s and 1s with 0s
// your approach on that is very wrong
StringBuilder sb = new StringBuilder();
for(int j=0;j<s1.length();j++){
if(s1.charAt(j)=='0') sb.append("1");
else if(s1.charAt(j)=='1') sb.append("0");
}
s1 = sb.toString();
/*
for(int j=0;j<s1.length();j++)
{
if(s1.charAt(j)==0)
{
s1.replace(s1.charAt(j),'1');
}
else
{
s1.replace(s1.charAt(j),'0');
}
}
*/
System.out.println(s1);
int decimal=0;
int k=0;
for(int m=s1.length()-1;m>=0;m--)
{
// you don't want the char code here but the int value of the char code
//decimal += (s1.charAt(m) * Math.pow(2, k));
decimal+=(Character.getNumericValue(s1.charAt(m))*Math.pow(2, k));
k++;
}
return decimal;
}
Additional Note: Don't get bigger then MAX_BITS = 31 or you need to work with long instead of int in your method.
First of all you have to assign the replaced String to the already defined variable that is,
s1.replace(s1.charAt(j),'1');
it should be
s1 = s1.replace(s1.charAt(j),'1');
and the next case is, when you are changing in that order it would change all the characters similar to matched case
refer Replace a character at a specific index in a string?
String.Replace(oldChar, newChar) method returns a new string resulting from replacing all occurrences of oldChar in given string with newChar. It does not perform change on the given string.
The problem (OK, one of the problems) is here:
if(s1.charAt(j)==0)
Characters in Java are actually integers, in the range 0 to 65535. Each of those numbers actually means the character corresponding to that number in the Unicode chart. The character '0' has the value 48, not 0. So when you've created a string of '0' and '1' characters, the characters will have the integer values 48 and 49. Naturally, when you compare this to the integer 0, you'll get false no matter what.
Try
if(s1.charAt(j)=='0')
(Note: OK, the other answer is right--replace does not work. Not only are you using it incorrectly, by not assigning the result, it's not the right method anyway, because s1.replace(s1.charAt(j),'1') replaces all '0' with '1' characters; it doesn't replace character j. If you specifically want to replace the j'th character in a String with something else, you'll need to use substring() and build a new string, not replace().)
A couple other things to note: (1) Integers are not "decimal" or "binary". When your method gets the num parameter, this is just a number, not a decimal number or a binary number. It's represented in your computer as a binary number (unless you're using something like a Burroughs 3500, but I think all of those died before Java was invented). But it really isn't considered decimal, binary, octal, hex, ternary, or whatever, until you do something that converts it to a String. (2) I know you said not to post alternative approaches, but you could replace the entire method with just one line: return ~num;. That complements all the bits. If you were thinking that you couldn't do this because num was a decimal number, see #1. (3) "Compliment" means to say something nice about somebody. If you're talking about flipping all the bits, the correct spelling is "complement".