I'm a beginner with java and one concept is rather unclear to me. I need to create a method that creates a new string by replicating another string. For example, if the String1 is "java" and it is specified that it needs to be repeated 4 times and each of them needs to be separated with a comma, the new string would look like this: java, java, java, java
However, the method should not print it, but only create a new string that is then printed in the main program. This is a problem for me, because I have trouble understanding, how can I use a loop to create something without printing it. I think that the following code would print it correctly:
public static void replicate(String str, int times) {
for (int i = 0; i < times; i++) {
System.out.print(str);
if (i < times -1) {
System.out.print(", ");
}
}
}
How could I transform it so that I could use the method to create a new string without printing it? I am assuming this is something super simple, but I just don't know at all how to do this, because every guide just uses examples of printing in these kinds of situations.
This is much better with Collections and join
import java.util.*;
public class Main
{
public static void main(String[] args)
{
String newstr=String.join(",", Collections.nCopies(3, "java"));
System.out.println(newstr);
}
}
Working fiddle-https://repl.it/repls/OfficialInvolvedObject
This is easy to do using the StringBuilder class, which can be used like this:
public static String replicate(String str, int times) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < times; i++) {
builder.append(str);
if (i < times - 1) {
builder.append(", ");
}
}
return builder.toString();
}
The following code should be useful for academic purposes in which you cannot use all of Java's libraries. You want to use a variable to store the repeated text and then return that variable to the main method for it to be printed. For non academic purposes or in cases when efficiency is a priority the java.lang.StringBuilder object should be used.
public static String replicate(String str, int times) {
String newString = "";
for (int i = 0; i < times; i++) {
newString = newString + str;
if(i<times-1){
newString = newString + ", ";
}
}
return newString;
}
One option is to use a StringBuilder, as exemplified by Emily's answer. Since the same delimiter is used each time another option is to use java.util.StringJoiner. Here's an example:
public static String replicate(String str, int times) {
StringJoiner joiner = new StringJoiner(", ");
for (int i = 0; i < times; i++) {
joiner.add(str);
}
return joiner.toString();
}
I am assuming this is something super simple
You are right. While the other answers show various helper classes, you can do it with re-assigning a single String variable already:
public static String replicate(String str, int times) {
String result="";
for (int i = 0; i < times; i++) {
result += str; //System.out.print(str);
if (i < times -1) {
result += ", "; //System.out.print(", ");
}
}
return result;
}
Or, if you do not worry about having to provide 0 copies:
public static String replicate(String str, int times) {
String result=str; // one copy, without comma
for (int i = 1; i < times; i++) {
result += ", " + str; // all the other copies have their commas
}
return result;
}
This latter "trick" can be used with StringBuilder too of course:
public static String replicate(String str, int times) {
StringBuilder result = new StringBuilder(str);
for (int i = 1; i < times; i++) {
result.append(", ");
result.append(str);
}
return result.toString();
}
Btw, it may be worth mentioning what there story about StringBuilder is: when Java sees something=string1+string2, internally it writes StringBuilder temp=new StringBuilder(string1); temp.append(string2); something=temp.toString() (of course it is an unnamed, internal variable, not "temp"). So a brand new StringBuilder object is created, appended, converted back to a brand new String and thrown away every time. That is why the suggested method is to have one, dedicated StringBuilder, use it many times, and get the result from it only once, at the end.
Related
I wrote a method to reduce a sequence of the same characters to a single character as follows. It seems its logic is correct while there is a room for improvement in terms of performance, according to my tutor. Could anyone shed some light on this?
Comments of aspects other than performance is also really appreciated.
public class RemoveRepetitions {
public static String remove(String input) {
String ret = "";
String last = "";
String[] stringArray = input.split("");
for(int j=0; j < stringArray.length; j++) {
if (! last.equals(stringArray[j]) ) {
ret += stringArray[j];
}
last = stringArray[j];
}
return ret;
}
public static void main(String[] args) {
System.out.println(RemoveRepetitions.remove("foobaarrbuzz"));
}
}
We can improve the performance by using StringBuilder instead of using string as string operations are costlier. Also, the split function is also not required (it will make the program slower as well).
Here is a way to solve this:
public static String remove(String input)
{
StringBuilder answer = new StringBuilder("");
int N = input.length();
int i = 0;
while (i < N)
{
char c = input.charAt(i);
answer.append( c );
while (i<N && input.charAt(i)==c)
++i;
}
return answer.toString();
}
The idea is to iterate over all characters of the input string and keep appending every new character to the answer and skip all the same consecutive characters.
Possible change which you could think of in your code is:
Time Complexity: Your code is achieving output in O(n) time complexity, which might be the best possible way.
Space Complexity: Your code is using extra memory space which arises due to splitting.
Question to ask: Can you achieve this output, without using the extra space for character array that you get after splitting the string? (as character by character traversal is possible directly on string).
I can provide you the code here but, it would be great if you could try it on your own, once you are done with your attempts
you can lookup for the best solution here (you are almost there)
https://www.geeksforgeeks.org/remove-consecutive-duplicates-string/
Good luck!
As mentioned before, it is much better to access the characters in the string using method String::charAt or at least by iterating a char array retrieved with String::toCharArray instead of splitting the input string into String array.
However, Java strings may contain characters exceeding basic multilingual plane of Unicode (e.g. emojis πππ, Chinese or Japanese characters etc.) and therefore String::codePointAt should be used. Respectively, Character.charCount should be used to calculate appropriate offset while iterating the input string.
Also the input string should be checked if it's null or empty, so the resulting code may look like this:
public static String dedup(String str) {
if (null == str || str.isEmpty()) {
return str;
}
int prev = -1;
int n = str.length();
System.out.println("length = " + n + " of [" + str + "], real length: " + str.codePointCount(0, n));
StringBuilder sb = new StringBuilder(n);
for (int i = 0; i < n; ) {
int cp = str.codePointAt(i);
if (i == 0 || cp != prev) {
sb.appendCodePoint(cp);
}
prev = cp;
i += Character.charCount(cp); // for emojis it returns 2
}
return sb.toString();
}
A version with String::charAt may look like this:
public static String dedup2(String str) {
if (null == str || str.isEmpty()) {
return str;
}
int n = str.length();
StringBuilder sb = new StringBuilder(n);
sb.append(str.charAt(0));
for (int i = 1; i < n; i++) {
if (str.charAt(i) != str.charAt(i - 1)) {
sb.append(str.charAt(i));
}
}
return sb.toString();
}
The following test proves that charAt fails to deduplicate repeated emojis:
System.out.println("codePoint: " + dedup ("πππππππ hello"));
System.out.println("charAt: " + dedup2("πππππππ hello"));
Output:
length = 20 of [πππππππ hello], real length: 13
codePoint: ππππ helo
charAt: πππππππ helo
For another assignment i needed to program a "number seperator", that splits any given int value into all of its digits and returns it to the main class as a String.
I have the program up and running but there's a small problem with my output.
public class NumberSeperator {
static String splitNumber(int zahl) {
String s = Integer.toString(zahl);
return s;
}
public static void main(String args[]) {
System.out.println("Input a Number: ");
int zahl = readInt();
String ziffern = splitNumber(zahl);
for (int i = 0; i < ziffern.length(); i++) {
System.out.print(ziffern.charAt(i) + ",");
}
}
}
The output of 1234 should be: 1,2,3,4
and the actual output is: 1,2,3,4,
At the risk of sounding extremely stupid, is there an easy fix to this?
How about printing first element without comma and rest in form ,nextElement like
one, two, three
^^^---------------- - before loop
^^^^^----------- - loop iteration
^^^^^^^---- - loop iteration
It can be achieved like:
if(ziffern.length()>0){
System.out.print(ziffern.charAt(0));
}
for(int i=1; i<ziffern.length(); i++){
System.out.print(", "+ziffern.charAt(i));
}
OR you can convert ziffern to String[] array first and use built-in solution which is: String.join(delimiter, data)
System.our.print(String.join(",", ziffern.split("")));
When it's the last iteration, just don't add it.
In the last iteration, it will make the comma empty so that you won't see it after the last value.
String comma=",";
for (int i = 0; i < ziffern.length(); i++) {
if (i == ziffern.length()-1) {
comma="";
}
System.out.print(ziffern.charAt(i) + comma);
}
with Java 8 and streams you can do it in a single command:
String join = Arrays.asList(ziffern.split(""))
.stream()
.collect(Collectors.joining(","));
System.out.println(join);
or with just plain java 8:
String join = String.join(",", ziffern.split(""));
System.out.println(join);
A simple one liner will do your job:
static String splitNumber(int zahl) {
return String.join(",", String.valueOf(zahl).split(""));
}
Quite often this occurs when you know you have at least two items to print. So here is how you could do it then.
String ziffern = splitNumber(zahl);
String output = ziffern[0];
for (int i = 1; i < ziffern.length(); i++) {
output = "," + ziffern[i];
}
System.out.println(output);
You can just output the string without the last character.
Your modified code should be:
public class NumberSeperator {
static String splitNumber(int zahl) {
String s = Integer.toString(zahl);
return s;
}
public static void main(String args[]) {
int zahl = 1234;
String s="";
String ziffern = splitNumber(zahl);
for (int i = 0; i < ziffern.length(); i++) {
s+=ziffern.charAt(i) + ",";
}
System.out.println(s.substring(0,s.length()-1));
}
I checked many discutions about the best way to concatenate many string In Java.
As i understood Stringbuilder is more efficient than the + operator.
Unfortunantly My question is a litlle bit different.
Given the string :"AAAAA", how can we concatenate it with n times the char '_',knowing that the '_' has to come before the String "AAAAA"
if n is equal to 3 and str="AAAAA", the result has to be the String "___AAAAA"
String str = "AAAAA";
for (int i=0;i<100;i++){
str="_"+str;
}
In my program i have a Longs String , so i have to use the efficient way.
Thank you
EDIT1:
As I have read some Solutions I discovered that I asked for Only One Case , SO I arrived to this Solution that i think is good:
public class Concatenation {
public static void main(String[] args) {
//so str is the String that i want to modify
StringBuilder str = new StringBuilder("AAAAA");
//As suggested
StringBuilder space = new StringBuilder();
for (int i = 0; i < 3; i++) {
space.append("_");
}
//another for loop to concatenate different char and not only the '_'
for (int i = 0; i < 3; i++) {
char next = getTheNewchar();
space.append(next);
}
space.append(str);
str = space;
System.out.println(str);
}
public static char getTheNewchar(){
//normally i return a rondom char, but for the case of simplicity i return the same char
return 'A';
}
}
Best way to concatenate Strings in Java: You don't.... Strings are immutable in Java. Each time you concatenate, you generate a new Object. Use StringBuilder instead.
StringBuilder sb = new StringBuilder();
for (int i=0;i<100;i++){
sb.append("_");
}
sb.append("AAAAA");
String str = sb.toString();
Go to char array, alloting the right size, fill the array, and sum it up back into a string.
Canβt beat that.
public String concat(char c, int l, String string) {
int sl = string.length();
char[] buf = new char[sl + l];
int pos = 0;
for (int i = 0; i < l; i++) {
buf[pos++] = c;
}
for (int i = 0; i < sl; i++) {
buf[pos++] = string.charAt(i);
}
return String.valueOf(buf);
}
I'd do something like:
import java.util.Arrays;
...
int numUnderbars = 3;
char[] underbarArray = new char[numUnderbars];
Arrays.fill(underbarArray, '_');
String output = String.valueOf(underbarArray) + "AAAA";
but the reality is that any of the solutions presented would likely be trivially different in run time.
If you do not like to write for loop use
org.apache.commons.lang.StringUtils class repeat(str,n) method.
Your code will be shorter:
String str=new StringBuilder(StringUtils.repeat("_",n)).append("AAAAA").toString();
BTW:
Actual answer to the question is in the code of that repeat method.
when 1 or 2 characters need to be repeated it uses char array in the loop, otherwise it uses StringBuilder append solution.
I am not very good at java so that's why some things might not make sense at all. I was just simply using code from bits I found online which I know is wrong.
My current issue is that it simply prints a blank code; I am not sure how to get it to print it like so:
Input:
APPLE
Output:
A
AP
APP
APPL
APPLE
Current Code:
import java.util.Scanner;
public class WordGrow
{
public static void main(String[]args)
{
//take your word input
//enter word as a parameter in WordGrow()
System.out.println("Please enter the word to *GROW*");
Scanner scan = new Scanner(System.in);
String theword = scan.next();
System.out.println(makeTree(theword, theword.length()));
}
public static String makeTree(String word, int len)
{
int count = 0;
//start with the first letter and print
//and add another letter each time the loop runs
if (word.length() > 0)
{
for(int i = 0; i < word.length();i++)
{
return word.substring(0, i++);
}
}
return (word.charAt(1) + makeTree(word, len));
}
}
Take Java out of it. Let's take this back to pen and paper.
First, look at the pattern you're printing out. How would you print out just one letter of that string? How would you print out two?
Let's start with that approach. Let's try to print out one letter in that string.
public void printStringChain(String word) {
System.out.println(word.substring(0, 1));
}
What about two letters?
public void printStringChain(String word) {
System.out.println(word.substring(0, 2));
}
What about word.length() letters?
public void printStringChain(String word) {
System.out.println(word.substring(0, word.length()));
}
The main thing I'm trying to get you to see is that there's a pattern here. In order to accomplish this, you likely need to go from zero to the length of your string in order to print out each line on its own.
Here's a start. I leave figuring out the nuance and barriers inside of the substring as an exercise for the reader.
public void printStringChain(String word) {
for (int i = 0; i < word.length(); i++) {
// the question mark relates to i, but in what way?
System.out.println(word.substring(0, (?)));
}
}
If recursion is not compulsory, you could simply iterate through the given String:
String str = "APPLE";
for(int x=0; x<str.length(); x++){
System.out.println(str.substring(0, x+1));
}
Output:
A
AP
APP
APPL
APPLE
One cannot return multiple times, at the first moment the result is passed on to the caller.
For String there is a buffering class for efficiency, the StringBuilder.
Including the empty string that would be:
public static String makeTree(String word) {
StringBuiilder sb = new StringBuilder();
for (int i = 0; i < word.length(); i++){
sb.append(word.substring(0, i));
sb.append("\r\n");
}
return sb.toString();
}
It uses the Windows end-of-line characters CR+LF aka \r\n.
You can make that platform independent, but you get the idea.
WITH RECURSION
public static String makeTree(String word)
{
if (word.length() <= 1){
return word;
}
return makeTree(word.subSequence(0, word.length()-1).toString()) + System.lineSeparator() + word;
}
What I am trying to do, is create a method, that has a string and a character as parameters, the method then takes the string and searches for the given character. If the string contains that character, it returns an array of integers of where the character showed up. Here is what I have so far:
public class Sheet {
public static void main(String[] args) {
String string = "bbnnbb";
String complete = null;
//*******
for(int i = 0; i < string.length(); i++){
complete = StringSearch(string,'n').toString();
}
//********
}
public static int[] StringSearch(String string, char lookfor) {
int[]num = new int[string.length()];
for(int i = 0; i < num.length; i++){
if(string.charAt(i)== lookfor){
num[i] = i;
}
}
return num;
}
}
The method works fine, and returns this:
0
0
2
3
0
0
What I am trying to do, is make those into 1 string so it would look like this "002300".
Is there any possible way of doing this? I have tried to do it in the starred area of the code, but I have had no success.
just do
StringBuffer strBuff = new StringBuffer();
for(int i = 0; i<str.length(); i++)
{
if(str.charAt(i) == reqChar)
{
strBuff.append(str.charAt(i));
}
else
{
strBuff.append('0');
}
}
return str.toString();
Just add the result to the existing string with the += operator
String complete = "";
for(...)
complete += StringSearch(string,'n').toString();
I would just use java's regex library, that way it's more flexible (eg if you want to look for more than just a single character). Plus it's highly optimized.
StringBuilder positions = "";
Pattern pattern = Pattern.compile(string);
Matcher matcher = pattern.matcher(lookfor);
while(matcher.find()){
positions.append(matcher.start());
}
return positions;
Updated with StringBuilder for better practices.
public static String StringSearch(String string, char lookfor) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < string.length; i++){
if(string.charAt(i) == lookfor)
sb.append(i);
else
sb.append("0");
}
return sb.toString();
}
Then you can just call it once, without a for loop. Not sure why you call it for every character in the string.
complete = StringSearch(string,'n');