I am trying to overwrite the compareTo in Java such that it works as follows. There will be two string arrays containing k strings each. The compareTo method will go through the words in order, comparing the kth element of each array. The arrays will then be sorted thusly. The code I have currently is as follows, but it does not work properly.
I need a return statement outside the for-loop. I'm not sure what this return statement should return, since one of the for-loop return statements will always be reached.
Also, am I using continue correctly here?
public int compareTo(WordNgram wg) {
for (int k = 0; k < (this.myWords).length; k++) {
String temp1 = (this.myWords)[k];
String temp2 = (wg.myWords)[k];
int last = temp1.compareTo(temp2);
if (last == 0) {
continue;
} else {
return last;
}
}
}
You want to compare the two string at the same location:
int last = temp1.compare(temp2);
Java compiler mandates all the end points must have a return statement. In your case you must return 0 at end so when both arrays contain completely equal strings the caller will know they are equal.
You should start listening to your compiler, because after looking at your code for 1 minute, I spotted two undefined states: this.myWords.length is 0 and the two words are equal.
Also, I personally find it very difficult to handle multiple method exit points with all possibilities for input considered and rather insert a single returning statement which makes debugging easier and the results more predictable. In your case for example, I would collect the results of compareTo in a collection if they differ from 0 so that after the for-loop has finished, you could decide at the state of this collection if 0 (empty collection) or the first value in the collection could be returned. I like this more formal approach, because it enforces you to think set-like as in "Give me all comparing results where compareTo results in anything else but 0. If this list is empty, the comparing result is 0, otherwise it is the first element of the list."
Related
I am new to Java, and I'm trying to figure out how to count Characters in the given string and threat a combination of two characters "eu" as a single character, and still count all other characters as one character.
And I want to do that using recursion.
Consider the following example.
Input:
"geugeu"
Desired output:
4 // g + eu + g + eu = 4
Current output:
2
I've been trying a lot and still can't seem to figure out how to implement it correctly.
My code:
public static int recursionCount(String str) {
if (str.length() == 1) {
return 0;
}
else {
String ch = str.substring(0, 2);
if (ch.equals("eu") {
return 1 + recursionCount(str.substring(1));
}
else {
return recursionCount(str.substring(1));
}
}
}
OP wants to count all characters in a string but adjacent characters "ae", "oe", "ue", and "eu" should be considered a single character and counted only once.
Below code does that:
public static int recursionCount(String str) {
int n;
n = str.length();
if(n <= 1) {
return n; // return 1 if one character left or 0 if empty string.
}
else {
String ch = str.substring(0, 2);
if(ch.equals("ae") || ch.equals("oe") || ch.equals("ue") || ch.equals("eu")) {
// consider as one character and skip next character
return 1 + recursionCount(str.substring(2));
}
else {
// don't skip next character
return 1 + recursionCount(str.substring(1));
}
}
}
Recursion explained
In order to address a particular task using Recursion, you need a firm understanding of how recursion works.
And the first thing you need to keep in mind is that every recursive solution should (either explicitly or implicitly) contain two parts: Base case and Recursive case.
Let's have a look at them closely:
Base case - a part that represents a simple edge-case (or a set of edge-cases), i.e. a situation in which recursion should terminate. The outcome for these edge-cases is known in advance. For this task, base case is when the given string is empty, and since there's nothing to count the return value should be 0. That is sufficient for the algorithm to work, outcomes for other inputs should be derived from the recursive case.
Recursive case - is the part of the method where recursive calls are made and where the main logic resides. Every recursive call eventually hits the base case and stars building its return value.
In the recursive case, we need to check whether the given string starts from a particular string like "eu". And for that we don't need to generate a substring (keep in mind that object creation is costful). instead we can use method String.startsWith() which checks if the bytes of the provided prefix string match the bytes at the beginning of this string which is chipper (reminder: starting from Java 9 String is backed by an array of bytes, and each character is represented either with one or two bytes depending on the character encoding) and we also don't bother about the length of the string because if the string is shorter than the prefix startsWith() will return false.
Implementation
That said, here's how an implementation might look:
public static int recursionCount(String str) {
if(str.isEmpty()) {
return 0;
}
return str.startsWith("eu") ?
1 + recursionCount(str.substring(2)) : 1 + recursionCount(str.substring(1));
}
Note: that besides from being able to implement a solution, you also need to evaluate it's Time and Space complexity.
In this case because we are creating a new string with every call time complexity is quadratic O(n^2) (reminder: creation of the new string requires allocating the memory to coping bytes of the original string). And worse case space complexity also would be O(n^2).
There's a way of solving this problem recursively in a linear time O(n) without generating a new string at every call. For that we need to introduce the second argument - current index, and each recursive call should advance this index either by 1 or by 2 (I'm not going to implement this solution and living it for OP/reader as an exercise).
In addition
In addition, here's a concise and simple non-recursive solution using String.replace():
public static int count(String str) {
return str.replace("eu", "_").length();
}
If you would need handle multiple combination of character (which were listed in the first version of the question) you can make use of the regular expressions with String.replaceAll():
public static int count(String str) {
return str.replaceAll("ue|au|oe|eu", "_").length();
}
Im doing a Java course and in one exercise I have to create three ArrayLists, ask the user to fill the first two with Integers, and then compare both ArrayLists.
The values that donĀ“t repeat are added to the third ArrayList. I already declared the ArrayLists, used Scanner to allow the user to fill the ArrayLists, and that part works.
The problem comes when I try to compare both ArrayLists. I get all sort of alerts in this line ("the if statement is redundant", "Integer values compared using == or !=","Flip operands of the binary operator", "Invert if").
I suspect that what I wrote after the if statement is not very clean, and that I could get some comments about that (Im not an expert in Java), but I do not understand the alerts that the IDE displays. The code compiles and runs just fine until it hits the nested loops. Please help! Thanks.
//Checking for values that dont repeat
for(int i=0;i<listVector1.size();i++){
for(int j=0;j<listVector2.size();i++){
if(listVector1.get(i)==listVector2.get(j)){//Im getting an alert here
repeats=true; //this boolean was previously declared
} else {
repeats=false;
}
if(repeats==false){
int newValue=listVector1.get(i);
listVector3.add(newValue);
}
}
}
First of all, you have a mistake in the second for loop. I expect you want increment j.
Second is comparing you must explicit cast your values from the array or use function equals.
Third your if statement must be out of your second loop. Because I expect you want to add number in third array only one time as it you find.
for(int i = 0; i < listVector1.size(); i++) {
for(int j = 0; j < listVector2.size(); j++) {
if (listVector1.get(i).equals(listVector2.get(j))) {
repeats = true;
break;
} else {
repeats = false;
}
}
if(!repeats){
int newValue=listVector1.get(i);
listVector3.add(newValue);
}
}
This is the real problem here.
Integer values compared using == or !=
The == operator compares the two object's reference. But what you actually want to do is compare the values stored in the reference.
So, you need to use the equals operator.
Or you could explicitly cast one of the values to int and use == on the values like
if(listVector1.get(i) == ((int)listVector2.get(j))){
repeats=true;
} else {
repeats=false;
}
For more reading, you'd google difference between == and equals operator.
I have list of Strings
for example
**united**abc
**united**abcd
abcd**united**
**united**abcde
asdasdad**united**
**united**a
it is sorted based on length of the strings, but my idea is to sort like
**united**a
**united**abc
**united**abcd
**united**abcde
abcd**united**
asdasdad**united**
so first comes strings where start with united and then others words ending with united. but I still need to keep the length order as well.
I tried this but this doesn't work
if (o1.name.toLowerCase().startsWith(query)) {
return#Comparator -1
} else if (o2.name.toLowerCase().startsWith(query)) {
return#Comparator 1
} else {
return#Comparator 0
}
It will be a lot more legible and thus less error-prone to combine comparator conditions using the Comparator.comparing and thenComparing methods:
list.sort(Comparator.comparing((String str) -> !str.startsWith(query))
.thenComparing(str -> !str.endsWith(query))
.thenComparingInt(String::length)
.thenComparing(Comparator.naturalOrder()));
The reason for the ! symbol is so that our trues will sort before falses.
The problem with your comparer is that it violates constraints when both inputs either start or end in query string. For example, when both o1 and o2's name start in "united", your comparer would return -1 both for o1.compareTo(o2) and its opposite o2.compareTo(o1), which is inconsistent, and therefore throws off the sorting algorithm.
You need to modify the code to check both sides for startsWith and endsWith before you proceed further:
String n1 = o1.name.toLowerCase();
String n2 = o2.name.toLowerCase();
// Both startsWith / both endsWith
if ((n1.startsWith(query) && n2.startsWith(query))
|| (n1.endsWith(query) && n2.endsWith(query))) {
return Integer.compare(n1.length(), n2.length());
}
// Only one startsWith
if (n1.startsWith(query)) {
return -1;
}
if (n2.startsWith(query)) {
return 1;
}
// only one endsWith
if (n1.endsWith(query)) {
return 1;
}
if (n2.endsWith(query)) {
return -1;
}
You need 3 comparators for readabilty.
One to find out if united is in the front and then order by that.
One to find out if united is in the back and then order by that.
One to find order if united isn't contained, or both have the same united priority eg. o1.unitedFront && o2.unitedFront or o1.unitedEnd && o2.unitedEnd.
You are currently not thinking about cases where both strings contain united, because you assume that if the first does, then other doesn't.
I have a strange problem when adding a value to a String array which is later involved in an array sort using a hash map. I have a filename XFR900a, and the XFR900 part is added to the array using the following code;
private ArrayList<String> Types = new ArrayList<String>();
...
Types.add(name.substring(0,(name.length() - 1));
System.out.println(name.substring(0,(name.length() - 1));
I even print the line which gives "XFR900", however the array sort later on behaves differently when I use the following code instead;
Types.add("XFR900");
System.out.println(name.substring(0,(name.length() - 1));
which is simply the substring part done manually, very confusing.
Are there any good alternatives to substring, as there must be some odd non ascii character in there?
Phil
UPDATE
Thanks for your comments everyone. Here is some of the code that later compares the string;
for (int i=0;i< matchedArray.size();i++){
//run through the arrays
if (last == matchedArray.get(i)) {
//add arrays to a data array
ArrayList data = new ArrayList();
data.add(matchedArray1.get(i));
data.add(matchedArray2.get(i));
data.add(matchedArray3.get(i));
data.add(matchedArray4.get(i));
data.add(matchedArray5.get(i));
//put into hash map
map.put(matchedArray.get(i), data);
}
else {
//TODO
System.out.println("DO NOT MATCH :" + last + "-" + matchedArray.get(i));
As you can see I have added a test System.out.println("DO NOT MATCH" ... and below is some the output;
DO NOT MATCH :FR99-XFR900
DO NOT MATCH :XFR900-XFR900
I only run the substring on the XFR900a filename. The problem is that for the test line to be printed last != matchedArray.get(i) however they are then the same when printed out to the display.
Phil
You should never use the == operator to compare the content of strings. == checks if it is the same object. Write last.equals(matchedArray.get(i)) instead. The equals() method checks if to object are equal, not if they are the same. In case of String it checks if the two strings consists of the same characters. This might eliminate your strange behaviour.
PS: The behaviour of == on string is a little unpredictable because the java virtual machine does some optimization. If two strings are equal it is possible that the jvm uses the same object for both. This is possible because String objects are immutable anyway. This would explain the difference in behaviour if you write down the substring manually. In the one case the jvm optimizes, in the other it doesn't.
Use .equals() rather than == because they are strings!
if (last.equals(matchedArray.get(i))) {}
Never use == operator if you wanted to check the value since operator will check the Object reference equality, use equals operator which check on the value not the reference i.e. for (int i=0;i< matchedArray.size();i++){
//run through the arrays
if (last.equals(matchedArray.get(i))) { // Line edited
//add arrays to a data array
ArrayList data = new ArrayList();
data.add(matchedArray1.get(i));
data.add(matchedArray2.get(i));
data.add(matchedArray3.get(i));
data.add(matchedArray4.get(i));
data.add(matchedArray5.get(i));
//put into hash map
map.put(matchedArray.get(i), data);
}
else {
//TODO
System.out.println("DO NOT MATCH :" + last + "-" + matchedArray.get(i));
I am trying to write a method that uses recursion to compare the strings str1 and str2 and determine which of them comes first alphabetically (i.e., according to the ordering used for words in a dictionary).
If str1 comes first alphabetically, the method should return int 1.
If str2 comes first alphabetically, the method should return the int 2.
If the two strings are the same, the method should return the int 0.
I know that there is a compareTo method in the Java API but i would like to know how to do this without this
This is what i have so far but i'm not entirely sure how to proceeded
} if (str1.length().equals(str2.length()))
return 0;
} else {
(str.substring(1, str.length()));
Any ideas would be greatly appreciated
Make a method int recursiveCompare(String string1, String string2, int index). Initially call it with index = 0. Compare string1.charAt(index) and string2.charAt(index), and if they're different, return 1 or 2. If they're the same, return recursiveCompare(string1, string2, index + 1).
Of course, you'll have to check the lengths of string1 and string2 before calling charAt(index). If they both reach the end at the same time, they're equal, so return 0. Otherwise, return the number of the one that has ended.
And yeah, recursion is pretty much the worst way to do this, LOL.
No recursion required... (Unless this is specifically required in the homework(?) assignement...)
As this looks a lot like homework, I'll just give a few hints
Use a integer variable, say i, to index from 0 to the length of shorter string.
As long as str1[i] == str2[i], and the last index value hasn't been reached, increment i.
If you do reach the last possible value for the index, then the shorter string comes first (or they are deemed equal if same length...)
Otherwise, compare this first character that differs, and decide which string is first accordingly... Could be as simple as:
return (str1[i] < str2[i]);
If recursion you must... (and it was readily said in other comments, this kind of problem is truly not a logical/valid candidate for recursion...)
The idea is to have a function with this kind of interface:
int RecursCompare(string str1, string str2, int i)
and which calls itself, passing the same values for str1 an str2 and passing the next value for i (i+1), as long as str1[i] == str2[i] AND neither str1 or str2 is at its end.
When this condidtion becomes false, recursion ends, and instead the function returns the appropriate value to signify tha Str1 is alphabetically before or after Str2.
#include<stdio.h>main(){ char str1[100],str2[100]; int i=0,k=0; puts("Enter string 1"); gets(str1); puts("Enter string 2"); gets(str2); i=comp(str1,str2,0); printf("\ncount is %d %d \n",i,strlen(str1)); (strlen(str1)==strlen(str2)) ?( (strlen(str1)==i) ? printf("Both are equal"):printf("Both are Not equal")):printf("Both are Not equal"); }int comp(char s1[], char s2[],int i){ printf("\n%c %c",s1[i],s2[i]); int sum=0,count =1; if((s1[i] != '\0')|| (s2[i]!='\0')) { if (s1[i] == s2[i]) { return (count += comp(s1,s2,++i)); } else { return 0; } } else { return 0; } return count; }