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.
Related
I am obviously new to java. I have this assignment where I am supposed to write a program which performs arithmetic operations on numbers expressed as a character string.
I don't know where to start. I have tried googling, looking through my book, big java, in the relevant sections but can't seem to find helpful information.
I found a program that have completed the same assignment but I want to learn write my own and understand how to go about.
I can show you one of the methods that he used.
I have bolded a few comments where I get confused.
public static String add(String num1, String num2) {
while (num1.length() > num2.length()) {
num2 = "0" + num2;
}
while (num1.length() < num2.length()) {
num1 = "0" + num1;
}
int carry = 0; // whats the point of this?
String result = "";
// look at the for loop bellow. I don't understand why he is converting the strings to ints this
// way? this doesn't even return the correct inputed numbers?
for (int i = 1; i <= num1.length(); i++) {
int digit1 = Character.getNumericValue(num1.charAt(num1.length() - i));
int digit2 = Character.getNumericValue(num2.charAt(num2.length() - i));
int sum = digit1 + digit2 + carry;
carry = sum / 10;
result = (sum % 10) + result;
// why is he dividing the sum with 10? If the user inputs a 5, would't the result become 0.5
// which isn't a valid int value? this line is also confusing
}
if (carry > 0) {
result = carry + result;
}
return result;
}
Any explanation or even guidance to a page where I am trying to do is explained would be very appreciated.
I found a program that have completed the same assignment but I want to learn write my own and understand how to go about.
That is the right idea. I suggest that you stop looking at the code that you found. (I'm sure that your teachers don't want you to look up the answers on the internet, and you will learn more from your homework if you don't do it.)
So how to proceed?
(I am assuming that you are supposed to code the methods to do the arithmetic, and not just convert the entire string to a primitive number or BigInteger and use them to do the arithmetic.)
Here's my suggested approach:
What you are trying to program is the equivalent of doing long addition with a pencil and paper. Like you were taught in primary school. So I suggest that you think of that pencil-and-paper procedure as an algorithm and work out how to express it as Java code. The first step is to make sure that you have the steps of this algorithm clearly in your head.
Try to break the larger problem into smaller sub-problems. One sub-problem could be how to convert a character representing a decimal digit into an integer; e.g. how to convert '1' to 1. Next sub-problem is adding two numbers in the range 0 to 9 and dealing with the "carry". A final sub-problem is converting an integer in the range 0 to 9 into the corresponding character.
Write sample Java code fragments for each sub-problem. If you have been taught about writing methods, some of the code fragments could be expressed as Java methods.
Then you assemble the solutions to the sub-problems into a solution for the entire problem. For example, adding two (positive!) numbers represented as strings involves looping over the digits, starting at the "right hand" end.
As part of your program, write a collection of test cases that you can use to automate the checking. For example:
String test1 = add("8", "3");
if (!test1.equals("11")) {
System.out.println("test1 incorrect: expected '11' go '" +
test1 + "'");
}
Hints:
You can "explode" a String to a char[] using the toCharArray method. Or you could use charAt to get characters individually.
You can convert between a char representing a digit and an int using Character methods or with some simple arithmetic.
You can use + to concatenate a string and a character, or a character and a string. Or you can use a StringBuilder.
If you need to deal with signed numbers, strip off and remember the sign, do the appropriate computation, and put it back; e.g. "-123 + -456" is "- (123 + 456)".
If you need to do long multiplication and long division, you can build them up from long addition and long subtraction.
You can convert a number in String format to a number in numeric format by “long n = Long. parseLong(String)” or “Long n = Long.valueOf(String)”. Then just add 2 long variables using a + sign. It will throw NumberFormatException if the String is not a number but a character. Throw that exception back to the caller.
The first part of the code pads both numbers to equal lengths.
e.g. "45" + "789" will be padded to "045" + "789"
The for loop evaluates one character at a time, starting from the right hand most.
iteration 1 -> (right most)
5 + 9 -> 14
when you divide an integer with another integer, you will always get an integer.
hence carry = 14/10 = 1 (note: not 1.4, but 1, because an int cannot have decimal places)
and the remainder is 14 % 10 = 4 (mod operation)
we now concatenate this remainder into "result" (which is "" empty)
result = (14%10)+ result; // value of result is now "4"
iteration 2 -> (second right most)
4+8 + (carry) = 4 + 8 + 1 = 13
same thing, there is a carry of 13/10 = 1
and the remainder is 13%10 = 3
we concatenate the remainder into result ("4")
result = (13%10) + result = 3 +"4" = "34"
iteration 3->
0 + 7 + 1 = 8
this time 8/10 will give you 0 (hence carry = 0)
and 8%10 will give a remainder of 8.
result = 8 + "34" = "834"
after all the numbers have been evaluated, the code checks if there are anymore carry. if the value is more than 0, then that value is added to the front of the result.
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").
This question already has answers here:
Java 8 stream's .min() and .max(): why does this compile?
(5 answers)
Closed 6 years ago.
I have written simple List with example values, and I wanted the stream to return max value from Stream. I know max() function takes Comparator but it turned out, I can pass also Integer::max (anyone can explain my, why?).
Moreover, program prints weird result, I inspected it "inside" and it looks OK, but after I get final result - they are not accurate.
Example:
#Test
public void testHowIntegerMaxWorksInStream() {
List<Integer> list = Arrays.asList(5,3,8);
Optional<Integer> op = list.stream().max((a, b) -> {
System.out.println("Input arguments a=" + a + ", b=" + b);
int max = Integer.max(a, b);
System.out.println("Returning max(a,b)=" + max);
return max;
});
System.out.println("Optional result=" + op.get());
}
Output:
Input arguments a=5, b=3
Returning max(a,b)=5
Input arguments a=5, b=8
Returning max(a,b)=8 // OK, Integer::max got 8.. but then ...
Optional result=5 // .. I got 5. WHY ???
My questions:
Why can I pass Integer::max in place of Comparator ?
Why my function returns 5 as a result while inside it's 8 ?
You're misunderstanding things. max(comparator) takes a comparator that compares integer. What you're doing is not comparing integers, i.e. telling if a is greater than b or not. You're taking the max of them and returning it. So you're saying that a is always greater than b, since you're always returning a positive number (your list only consists of positive numbers). A Comparator returns:
a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
What you need to do is
public void testHowIntegerMaxWorksInStream() {
List<Integer> list = Arrays.asList(5,3,8);
Optional<Integer> op = list.stream().max((a, b) -> {
int compare = Integer.compare(a, b);
return compare;
});
System.out.println("Optional result=" + op.get());
}
i.e. calling Integer.compare instead of max, which does exactly that:
Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
For the second part of your question, refer to :: (double colon) operator in Java 8. It is called a method-refence. So another way to write it is:
List<Integer> list = Arrays.asList(5,3,8);
Optional<Integer> op = list.stream().max(Integer::compare);
System.out.println("Optional result=" + op.get());
The reason that Integer.max, unfortunately, compiles in place of a comparator is that its return type fits what is expected by stream's max method: the result of a comparison is an int, and the result of comparing two ints is an int as well. However, the result returned by Integer.max is inconsistent with what stream's max expects, which explains incorrect result: for example, if you pass (5, 8) to Integer.max it returns 8, a positive number; stream's max, however, interprets all positive numbers as an indication that the first parameter is greater than the second, which is incorrect in this situation.
The only reason why this compiles is that your comparator returns an int. This wouldn't work with Double or BigInteger.
Because you create Comparator that always returns the first element to be the greatest.
If you compare A and B, you should return -1 if A is smaller. You return the Integer.max of A and B, which, in your case, is always >0.
(a,b) -> {
if (a>b) return 1; // <-- you return a positive value always, so stream.max() thinks 5>8 :)
if (a<b) return -1;
if (a==b) return 0;
}
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()"
Is there a way to convert a series of integers to a String according to the ASCII table. I want to take the ASCII value of a String and convert it back to a String. For example,
97098097=> "aba"
I really need an effective way of taking an integer and converting it to a String according to its ASCII value. This method must also take into account the fact that there is no zero in front of the '9' when the String "aba" has an ASCII value of 97098097 as 'a' has an ASCII value of 097 and a String "dee" has one of 100101101. This means that not every number will have an ASCII value that has a number of digits that is a multiple of three.
If you have any misunderstandings of what I'm trying to do please let me know.
No lookup table required.
while (string.length() % 3 != 0)
{
string = '0' + string;
}
String result = "";
for (int i = 0; i < string.length(); i += 3)
{
result += (char)(Integer.parseInt(string.substring(i, i + 3)));
}
First, I would create some sort of lookup table in your code with all the ascii values and their String equivalent. Then take the big int and convert it to a String. Then do the mod of 3 with the length of your bigint string to determine if you need to add 1, 2, or no 0's to the front of it. Then just grab every 3 integers from the front of the number, compare it to the lookup table, and append the corresponding value to your result string.
Example:
Given 97098097
You would convert it to: "97098097"
Then you do a mod with 3 resulting in a value of 1, so 1 zero needs to be added.
Append 1 zero: "097098097"
Then grab every 3 from the front and compare to look up table:
097 -> a, so result += "a"
098 -> b, so result += "b"
097 -> a, so result += "a"
You end with result being "aba"