Related
I'm working on an assignment and the code is working perfectly, except for one small little problem.
For example at the end it's supposed to say, "t,e,s,t" but instead it prints out "t,e,s,t,".
import javax.swing.JOptionPane;
public class program {
public static int divide(String input) {
int length=0;
String output = "";
for (int i=0; i<input.length(); i++) {
length++;
output += input.charAt(i);
output += ",";
}
JOptionPane.showMessageDialog(null, "Eingabe: " +input+ "\nAnzahl der Zeichen: " +length+ "\nZeichen: \n" +output);
return length;
}
}
I'd just like to say for those who are planning on giving tips, please note that this is an assignment so I'm not really allowed to make any MAJOR changes to it. This program HAS to be:
Solved using a for loop
The output HAS to be in JOptionPane
It has to be in a method (for I'll have to write an inputDialog later in the main-method, but that's unimportant right now).
My only problem with it, for example the output would have to say (I'll translate the output in english, since I'm at an austrian school) if the string was "hello", the program would say "letters: h, e, l, l, o" but instead it says "h, e, l, l, o," with a comma at the end, how do I get rid of it?
(Also sorry if I messed up any variables, I renamed them all from German to English for this post so I hope I didn't mess any of them up)
One of the possibilities is to print comma not after each character, but before every character except the first one.
You only want to add a comma if there is more data to come after. So you can do it in two ways:
add the comma before the text if there's already something in the string:
String output = "";
for (int i=0; i<input.length(); i++) {
length++;
if (output.length() > 0) output += ",";
output += input.charAt(i);
}
add the comma after unless it's the last element:
String output = "";
for (int i=0; i<input.length(); i++) {
length++;
output += input.charAt(i);
if (i < input.length() - 1) output += ",";
}
Personally I like the first way.
Hello I used an if statement to check if we are at the first letter and if we are then we don't write a comma, here is the code:
{
int length = 0;
String output = "";
int i = 0;
for ( i = 0; i < input.length(); i++)
{
if(i == 0)
{
length++;
output += input.charAt(i);
}
else
{
output += ",";
output += input.charAt(i);
length++;
}
}
Console.WriteLine(output);
}
You only need to check whether you are at the last character, and if you are, then break out from the loop.
for (int i=0; i<input.length(); i++) {
length++; //you do not seem to need this
output += input.charAt(i);
if (i==(input.length()-1)) break; //checking whether we are at the last character
output += ",";
}
Two additional notes:
Please follow the Java Naming Conventions and use PascalCase for your class names, this is very important;
It would make your code much more efficient if you'd use StringBuilder instead of String, to concatenate characters and dynamically build your string. String is immutable and per each concatenation, you're actually creating a new instance of it, which is expensive.
I would use a StringJoiner
StringJoiner output = new StringJoiner(",");
for (int i = 0; i < input.length(); i++) {
length++;
output.add(input.substring(i, i + 1));
}
JOptionPane.showMessageDialog(… + output.toString());
so You are not allowed to use StringJoiner
String output = "";
String comma = "";
for (int i = 0; i < input.length(); i++) {
length++;
output += comma;
output += input.charAt(i);
comma = ",";
}
Your loop iterates through every character, appending both the character and a comma. This includes the final character. You need to find a way to avoid adding a comma after the final iteration;
Using String and appending characters one by one is very inefficient. This is what StringBuilder is designed for;
What is the purpose of the length variable? It can be replaced with input.length() - 1;
String.format() makes your code easier to read rather than chaining together string concatenations;
Don't be afraid to use a healthy amount of spacing throughout your code. It is much harder to read otherwise.
Something like this should work well:
public static int divide(String input) {
int length = input.length() - 1;
String output;
if (input.length() == 0) output = input;
else {
StringBuilder outputBuilder = new StringBuilder(input.charAt(0));
for (int i = 1; i < input.length(); i++) {
outputBuilder.append(',').append(input.charAt(i));
}
output = outputBuilder.toString();
}
JOptionPane.showMessageDialog(null, String.format("Eingabe: %s\nAnzahl der Zeichen: %d\nZeichen: \n%s", input, length, output);
return length;
}
Once you learn, use a StringJoiner or similar modern device. My favourite link is at the bottom. There will also be a time when you learn to use a StringBuilder or StringBuffer for assembling a string.
In the meantime, I still like what I learned in my first year of programming: when one iteration through a loop needs to be different, take it out of the loop. In my experience this often gives the clearest code. In your case:
String input = "Wort";
String output = "" + input.charAt(0);
for (int i = 1; i < input.length(); i++) {
output += ",";
output += input.charAt(i);
}
System.out.println("Zeichen: " + output);
Output:
Zeichen: W,o,r,t
In this case I have taken the first character outside the loop and add it to the output (without comma) already in the declaration of output. The loop starts from index 1 (not 0). Inside the loop I have to add the comma before adding the next char. In other cases one may put the last item outside the loop instead, the result will be the same.
Links
Answer by Lii to a similar question demonstrating all of String.join(), Collectors.joining() and StringJoiner.
StringBuilder vs String concatenation in toString() in Java
I am a beginner in Java. Below is a piece of code that I wrote. the purpose is to add a space between each upper case character for example for string="ILoveMyDog" to
"I Love My Dog". However the outcome of this code is "ILoveMy Dog". Can someone help me figured out what is wrong? upperCaseList is another method to extract the index of all uppercase character and put them into a list, and I am pretty sure that part is correct
for (int i = 0; i < upperCaseList.size(); i++) {
newStr = w.replace(w.substring(upperCaseList.get(i), upperCaseList.get(i)+1), " "+ w.substring(upperCaseList.get(i), upperCaseList.get(i)+1));
}
return newStr
It is because you are overwriting the result of String.replace by reassigning newStr inside the loop. So, you only see the effect of the last replacement.
Assuming the content of upperCaseList is 1, 5, 7.
After Loop iteration 1, newStr has I LoveMyDog
After Loop iteration 2, newStr has ILove MyDog (you are not using the previous result, rather using the original string)
After Loop iteration 3, newStr has ILoveMy Dog
Try this,
String newStr = w;
for (int i = 0; i < upperCaseList.size(); i++) {
newStr = newStr.replace(w.substring(upperCaseList.get(i), upperCaseList.get(i)+1), " "+ w.substring(upperCaseList.get(i), upperCaseList.get(i)+1));
}
There are plenty of ways to solve this though. Rather than storing the list of indices containing the uppercase characters and using String.substring and String.replace, you can use StringBuilder to build up the string from the original string by looping through the characters and checking if it is upper/lower cased.
StringBuilder resultBuilder = new StringBuilder();
for (int i = 1; i < w.length(); i++) { //Note: Starting at index 1
if (Character.isUpperCase(w.charAt(i))) {
resultBuilder.append(" ")
.append(w.charAt(i));
} else {
resultBuilder.append(w.charAt(i));
}
}
System.out.println(resultBuilder.toString());
Not sure how you are creating the upperCaseList, I suggest to have one loop for all. Hope below code will work for your requirement.
public void test(){
String str ="ILoveMyDog";
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i< str.length() ; i++) {
if(Character.isUpperCase(str.charAt(i))){
//add space
strBuilder.append(" ");
}
//add the orginal char
strBuilder.append(str.charAt(i));
}
//use toString method
System.out.println(strBuilder.toString());
}
I have a JList model (listModelGrid) with items with labels like this:
LastName, FirstName Spouse // e.g. This is 1st list item with labels
Children // e.g. This is 2nd list item with labels
Street // e.g. This is 3rd list item with labels
City, State Postal // e.g. This is 4th list item with labels
I want to replace Labels with ResultSet.getString method like this:
String labels = "";
labels += resultSet.getString("LastName")+", "+resultSet.getString("FirstName")+" "+
resultSet.getString("Spouse") + "\n";
labels += resultSet.getString("Children") + "\n";
labels += resultSet.getString("Street") + "\n";
labels += resultSet.getString("City")+", "+resultSet.getString("State")+" "+
resultSet.getString("Postal");
I have tried it but stuck in loops:
private String getPrintingLabels(ResultSet rs) throws SQLException {
String str = "";
for (int i = 0; i < listModelGrid.getSize(); i++) {
String element = String.valueOf(listModelGrid.getElementAt(i));
String[] lbls = element.split(",\\s");
str += rs.getString(lbls[0])+", ";
for(int j = 1; j < lbls.length ; j++) {
// Stuck on her
}
String[] lbls2 = element.split("\\s");
str += rs.getString(lbls2[0])+" ";
for(int j = 1; j < lbls2.length ; j++) {
// Stuck on her
}
}
return str;
}
Thanks in advance!
The code in your method is written in a little complicated way.
I have used regex and simplified the code you wanted to write and here it is.
private String getPrintingLabels(ResultSet rs) throws SQLException {
Pattern p = Pattern.compile("([a-zA-Z]+)(,? )?");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < listModelGrid.getSize(); i++) {
String element = String.valueOf(listModelGrid.getElementAt(i));
Matcher m = p.matcher(element);
while(m.find()) {
sb.append(rs.getString(m.group(1)));
if (m.group(2) != null) {
sb.append(m.group(2));
}
}
sb.append(System.getProperty("line.separator")); // helps correctly insert a new line for any platform linux/windows/any
}
System.out.println(sb.toString());
return sb.toString();
}
I don't know if you are familiar with regex but by using regex your job is done quite easily. Also, using String concatenation is not a good idea specially when you have to do it quite much hence I have used StringBuild for same purpose. Also used line.separator property so no matter in what platform you run the code it will have appropriate line in your string. Just use my method instead of yours and see if the desired string the one you wanted.
Also in my code, you won't have to manually manage inserting ", " or " " as that is done automatically as it is present in the string.
Also make sure you import these two or any needed imports,
import java.util.regex.Matcher;
import java.util.regex.Pattern;
I'm pretty new to java and i am not understanding how i would combine these two things. What i am trying to do is reverse the list while also removing the space and capslock in between the letters and add something at the end to the output. Can you tell me what is wrong with what I am doing? This is to be created using a string builder
StringBuilder sb = new StringBuilder("We need ");
for (int i = tools.length - 1; i >= 0; i--) {
sb.append(tools[i]);
}
this part is gonna reverse the list and
for (String s : tools) {
sb.append(s.toLowerCase().trim() + "s, ");
}
this part is gonna lowercase and trim all the non essential stuff. How do I combine these two parts together when Im coding. Really not getting it
so for example if the input is an array of list
String[] tools = {"\tfood", "TABLE", " car ", "Phone"};
the output is going to be We need phones, cars, tables, foods and much more.
StringBuilder sb = new StringBuilder("We need ");
StringBuilder sbend = new StringBuilder();
for (int i = tools.length - 1; i >= 0; i--) {
sb.append(i).append(tools[i]);
sbend.append(tools[tools.length-i-1].toLowerCase().trim() + "s, ");
}
sb.append(sbend);
Just have two stringbuilders. Forget using string functions on integers. integers can't be put to lowercase or trimmed.
For your loop issue you first put your first line items in the first string builder and the reverse part in the second.
then when the loop is finished you join the two.
If this is the output you are expecting
We need phone, car, table, food
Then maybe you can try something like this-
for (int i = tools.length - 1; i >= 0; i--) {
sb.append(tools[i].toLowerCase().replaceAll("\\s+", ""));
if (i != 0) {
sb.append(", ");
}
}
Using StringBuilder and String, it seems to be as simple as below:
StringBuilder sb = new StringBuilder("We need ");
String s;
sb.reverse();
s = sb.substring(0).toLowerCase().replaceAll("\\s+","");
System.out.println(s);
Using only StringBuilder:
StringBuilder sb = new StringBuilder("We need ");
StringBuilder sb0 = new StringBuilder();
for (int i = sb.length() - 1; i >= 0; i--) {
sb0.append(sb.substring(i, i+1).toLowerCase().replace(" ", ""));
}
System.out.println(sb0);
String[] tools = {"\tfood", "TABLE", " car ", "Phone" };
StringBuilder need = new StringBuilder( "We need " );
String del = "";
for( int i = tools.length - 1; i >= 0; --i ){
need.append( del );
need.append( tools[i].trim().toLowerCase() );
need.append( "s" );
del = ", ";
}
need.append( " and much more." );
System.out.println( need.toString() );
This prints
We need phones, cars, tables, foods and much more.
Is there a way to determine if the loop is iterating for the last time. My code looks something like this:
int[] array = {1, 2, 3...};
StringBuilder builder = new StringBuilder();
for(int i : array)
{
builder.append("" + i);
if(!lastiteration)
builder.append(",");
}
Now the thing is I don't want to append the comma in the last iteration. Now is there a way to determine if it is the last iteration or am I stuck with the for loop or using an external counter to keep track.
Another alternative is to append the comma before you append i, just not on the first iteration. (Please don't use "" + i, by the way - you don't really want concatenation here, and StringBuilder has a perfectly good append(int) overload.)
int[] array = {1, 2, 3...};
StringBuilder builder = new StringBuilder();
for (int i : array) {
if (builder.length() != 0) {
builder.append(",");
}
builder.append(i);
}
The nice thing about this is that it will work with any Iterable - you can't always index things. (The "add the comma and then remove it at the end" is a nice suggestion when you're really using StringBuilder - but it doesn't work for things like writing to streams. It's possibly the best approach for this exact problem though.)
Another way to do this:
String delim = "";
for (int i : ints) {
sb.append(delim).append(i);
delim = ",";
}
Update: For Java 8, you now have Collectors
It might be easier to always append. And then, when you're done with your loop, just remove the final character. Tons less conditionals that way too.
You can use StringBuilder's deleteCharAt(int index) with index being length() - 1
Maybe you are using the wrong tool for the Job.
This is more manual than what you are doing but it's in a way more elegant if not a bit "old school"
StringBuffer buffer = new StringBuffer();
Iterator iter = s.iterator();
while (iter.hasNext()) {
buffer.append(iter.next());
if (iter.hasNext()) {
buffer.append(delimiter);
}
}
This is almost a repeat of this StackOverflow question. What you want is StringUtils, and to call the join method.
StringUtils.join(strArr, ',');
Another solution (perhaps the most efficient)
int[] array = {1, 2, 3};
StringBuilder builder = new StringBuilder();
if (array.length != 0) {
builder.append(array[0]);
for (int i = 1; i < array.length; i++ )
{
builder.append(",");
builder.append(array[i]);
}
}
keep it simple and use a standard for loop:
for(int i = 0 ; i < array.length ; i ++ ){
builder.append(array[i]);
if( i != array.length - 1 ){
builder.append(',');
}
}
or just use apache commons-lang StringUtils.join()
Explicit loops always work better than implicit ones.
builder.append( "" + array[0] );
for( int i = 1; i != array.length; i += 1 ) {
builder.append( ", " + array[i] );
}
You should wrap the whole thing in an if-statement just in case you're dealing with a zero-length array.
As toolkit mentioned, in Java 8 we now have Collectors. Here's what the code would look like:
String joined = array.stream().map(Object::toString).collect(Collectors.joining(", "));
I think that does exactly what you're looking for, and it's a pattern you could use for many other things.
If you convert it to a classic index loop, yes.
Or you could just delete the last comma after it's done. Like so:
int[] array = {1, 2, 3...};
StringBuilder
builder = new StringBuilder();
for(int i : array)
{
builder.append(i + ",");
}
if(builder.charAt((builder.length() - 1) == ','))
builder.deleteCharAt(builder.length() - 1);
Me, I just use StringUtils.join() from commons-lang.
You need Class Separator.
Separator s = new Separator(", ");
for(int i : array)
{
builder.append(s).append(i);
}
The implementation of class Separator is straight forward. It wraps a string that is returned on every call of toString() except for the first call, which returns an empty string.
Based on java.util.AbstractCollection.toString(), it exits early to avoid the delimiter.
StringBuffer buffer = new StringBuffer();
Iterator iter = s.iterator();
for (;;) {
buffer.append(iter.next());
if (! iter.hasNext())
break;
buffer.append(delimiter);
}
It's efficient and elegant, but not as self-evident as some of the other answers.
Here is a solution:
int[] array = {1, 2, 3...};
StringBuilder builder = new StringBuilder();
bool firstiteration=true;
for(int i : array)
{
if(!firstiteration)
builder.append(",");
builder.append("" + i);
firstiteration=false;
}
Look for the first iteration :)
Yet another option.
StringBuilder builder = new StringBuilder();
for(int i : array)
builder.append(',').append(i);
String text = builder.toString();
if (text.startsWith(",")) text=text.substring(1);
Many of the solutions described here are a bit over the top, IMHO, especially those that rely on external libraries. There is a nice clean, clear idiom for achieving a comma separated list that I have always used. It relies on the conditional (?) operator:
Edit: Original solution correct, but non-optimal according to comments. Trying a second time:
int[] array = {1, 2, 3};
StringBuilder builder = new StringBuilder();
for (int i = 0 ; i < array.length; i++)
builder.append(i == 0 ? "" : ",").append(array[i]);
There you go, in 4 lines of code including the declaration of the array and the StringBuilder.
Here's a SSCCE benchmark I ran (related to what I had to implement) with these results:
elapsed time with checks at every iteration: 12055(ms)
elapsed time with deletion at the end: 11977(ms)
On my example at least, skipping the check at every iteration isn't noticeably faster especially for sane volumes of data, but it is faster.
import java.util.ArrayList;
import java.util.List;
public class TestCommas {
public static String GetUrlsIn(int aProjectID, List<String> aUrls, boolean aPreferChecks)
{
if (aPreferChecks) {
StringBuffer sql = new StringBuffer("select * from mytable_" + aProjectID + " WHERE hash IN ");
StringBuffer inHashes = new StringBuffer("(");
StringBuffer inURLs = new StringBuffer("(");
if (aUrls.size() > 0)
{
for (String url : aUrls)
{
if (inHashes.length() > 0) {
inHashes.append(",");
inURLs.append(",");
}
inHashes.append(url.hashCode());
inURLs.append("\"").append(url.replace("\"", "\\\"")).append("\"");//.append(",");
}
}
inHashes.append(")");
inURLs.append(")");
return sql.append(inHashes).append(" AND url IN ").append(inURLs).toString();
}
else {
StringBuffer sql = new StringBuffer("select * from mytable" + aProjectID + " WHERE hash IN ");
StringBuffer inHashes = new StringBuffer("(");
StringBuffer inURLs = new StringBuffer("(");
if (aUrls.size() > 0)
{
for (String url : aUrls)
{
inHashes.append(url.hashCode()).append(",");
inURLs.append("\"").append(url.replace("\"", "\\\"")).append("\"").append(",");
}
}
inHashes.deleteCharAt(inHashes.length()-1);
inURLs.deleteCharAt(inURLs.length()-1);
inHashes.append(")");
inURLs.append(")");
return sql.append(inHashes).append(" AND url IN ").append(inURLs).toString();
}
}
public static void main(String[] args) {
List<String> urls = new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
urls.add("http://www.google.com/" + System.currentTimeMillis());
urls.add("http://www.yahoo.com/" + System.currentTimeMillis());
urls.add("http://www.bing.com/" + System.currentTimeMillis());
}
long startTime = System.currentTimeMillis();
for (int i = 0; i < 300; i++) {
GetUrlsIn(5, urls, true);
}
long endTime = System.currentTimeMillis();
System.out.println("elapsed time with checks at every iteration: " + (endTime-startTime) + "(ms)");
startTime = System.currentTimeMillis();
for (int i = 0; i < 300; i++) {
GetUrlsIn(5, urls, false);
}
endTime = System.currentTimeMillis();
System.out.println("elapsed time with deletion at the end: " + (endTime-startTime) + "(ms)");
}
}
Another approach is to have the length of the array (if available) stored in a separate variable (more efficient than re-checking the length each time). You can then compare your index to that length to determine whether or not to add the final comma.
EDIT: Another consideration is weighing the performance cost of removing a final character (which may cause a string copy) against having a conditional be checked in each iteration.
If you're only turning an array into a comma delimited array, many languages have a join function for exactly this. It turns an array into a string with a delimiter between each element.
In this case there is really no need to know if it is the last repetition.
There are many ways we can solve this. One way would be:
String del = null;
for(int i : array)
{
if (del != null)
builder.append(del);
else
del = ",";
builder.append(i);
}
Two alternate paths here:
1: Apache Commons String Utils
2: Keep a boolean called first, set to true. In each iteration, if first is false, append your comma; after that, set first to false.
Since its a fixed array, it would be easier simply to avoid the enhanced for... If the Object is a collection an iterator would be easier.
int nums[] = getNumbersArray();
StringBuilder builder = new StringBuilder();
// non enhanced version
for(int i = 0; i < nums.length; i++){
builder.append(nums[i]);
if(i < nums.length - 1){
builder.append(",");
}
}
//using iterator
Iterator<int> numIter = Arrays.asList(nums).iterator();
while(numIter.hasNext()){
int num = numIter.next();
builder.append(num);
if(numIter.hasNext()){
builder.append(",");
}
}
You can use StringJoiner.
int[] array = { 1, 2, 3 };
StringJoiner stringJoiner = new StringJoiner(",");
for (int i : array) {
stringJoiner.add(String.valueOf(i));
}
System.out.println(stringJoiner);