How to use a loop in a toString? - java

I need to print the name of the shop (this method is in the Shop class) as well as the product name (which is an arraylist) and the price of the product ( which is done using a getter from the class Product). I want to loop through all the products in the arraylist, how can I do that ?
Please if something is not clear comment it and I will edit the question to make it clearer.
public String toString()
{
for(int i=0; i<products.size();i++)
{
return "Shop"+"["+"name"+" = "+name+","+"Product name"+" = "+products.get(i).getName()+", "+"Price"+" = "+products.get(i).getPrice()+"]";
}
return null;
}
This is wrong as the i++ is a dead code which means that the loop will execute once. Any help please ?
Thanks for your time

Use StringBuilder:
public String toString() {
StringBuilder sb = new StringBuilder("Shop").append("[name = ").append(name)
for (Product product : products) {
sb.append(",")
.append("Product name = ").append(product.getName())
.append(", Price = ").append(product.getPrice())
.append("]");
}
return sb.toString();
}
Note:
Do not use + inside the loop to join strings (as accepted answer did) as it will create a stringbuilder in each iteration to join the strings, and then append it to the outer stringbuilder.

Using a return statement will end the function's execution. Here's what you want to do instead.
public String toString()
{
StringBuilder result = new StringBuilder();
result.append("Shop [ name = "+name+" ");
for(Product p : products)
{
result.append("Product name"+" = "+p.getName()+", "+"Price"+" = "+p.getPrice()+" ");
}
result.append("]");
return result.toString();
}

You could use StringJoiner ( https://docs.oracle.com/javase/8/docs/api/java/util/StringJoiner.html )
public String toString(){
StringJoiner string = new StringJoiner(", ", name + "[", "]");
for (Product p : list) {
string.add("Product name:" + p.getName()).add("Product value:"+p.getValue());
}
return string.toString();
}
Output:
Shop[Product name:Teste, Product value:1.0, Product name:teste2, Product value:2.0]

You can use Guava Objects Class it facilitates to build the object toString().They changed it recently to MoreObjects.ToStringHelper
public String toString(){
ToStringHelper toStringHelper = MoreObjects.toStringHelper(this);
for (Product p : products)
{
toStringHelper.add("name", p.name);
toStringHelper.add("Product name", p.getName();
}
return toStringHelper.toString();
}

If you have a small collection, you can always just concatenate strings with +.
Creating a StringBuilder provides unnecessary overhead for small examples.
Other than that, compiler will optimise that part of code If it provides improvement to the performance.
public String toString() {
String str = "Shop [name = " + name + " ";
for (Product product : products) {
str += ", Product name = " + product.getName();
str += ", Price = " + product.getPrice() + "]";
}
return str;
}

Related

How to print different parts of a List in Java

I want to know how to print a List in Java where in each position there is a String and an int.
List pasajeros = new ArrayList();
I insert the data like this:
public void insert(List a) {
System.out.print("Name: ");
name= sc.nextLine();
System.out.print("Number: ");
number= sc.nextInt();
ClassName aero = new ClassName(name, number);
a.add(aero);
}
}
And it seems to work like this, but in the syso gives me an error.
So you have a list of ClassName.
To print them, you can simply use a for loop:
List<ClassName> pasajeros = new ArrayList<>();
// + insert elements
for (ClassName cn : pasajeros) {
System.out.println("Name: " + cn.getName() + ", number: " + cn.getNumber());
}
You are printing an object without overriding the toString method..
list.Aerolinea#154617c means you are printing the objects hashcode..
so your problem is not at inserting, is at printing out the objects that the list is holding, in this case your Aerolinea class must override properly the toString method.
something like:
class Aerolinea {
private String nombre;
private String apellido;
#Override
public String toString() {
return "Aerolinea [nombre=" + nombre + ", apellido=" + apellido + "]";
}
}
Try like put method toString in your class...
public class Aerolinea {
String nombre;
.......
.......
public String toString() {
return "nombre" = nombre;
}
}
Ok I fixed it finally, it was silly...
I forgot to write < ClassName> in the method. Here is the final code
public void vertodo(List<Aerolinea> a) {
for (Aerolinea cn : a) {
System.out.println("Name: " + cn.name+ " ID: " + cn.id);
}
}
since I had created it like List pasajeros = new ArrayList();, then I changed it to List<Aerolinea> pasajeros = new ArrayList();.
Although I can't write the final <> empty after ArrayList as some have recommended.

toString method in Java to print a symbol table

I'm doing a project where I build a simple symbol table consisting of two arrays : ArrayOfKeys and ArrayOfValues.
The keys are words and the values are the frequencies of each word in a text.
I need to write a toString method for my ST class using this model:
public String toString() {
// write your toString() method here
}
Suppose the words "aaa" and "bbb" are read from the text and inserted in the ST.
The toString method will be called like this:
StdOut.println("Let's see ST1 with 4 pairs key-val: " + st1);
where "st1" is an instance of the ST class.
The output should be this:
Let's see ST1 with 4 pairs key-val: {'aaa': 1 , 'bbb': 1}
As I see, the entire symbol table should be printed in the return statement of the toString() method, because it needs to return a String. I don't know how to do this, let alone in the format shown above.
The best I could try was:
return (arrayOfKeys + ":" + arrayOfValues);
PS: I'm using Java version 1.8.0_121.
One relatively neat (IMHO) approach is to create a stream of the indexes the arrays have and let Collectors.joining do the heavy lifting for you:
String result =
IntStream.range(0, arrayOfKeys.length)
.mapToObj(i -> "'" + arrayOfKeys[i] + "': " + arrayOfValues[i])
.collect(Collectors.joining(" , ", "{", "}"));
You can try using StringBuilder to generate the string. Code should look something like below:
public String toString() {
StringBuilder sb = new StringBuilder("Let's see ST1 with 4 pairs key-val: {");
for(int i = 0; i< arrayOfKeys.size();i++) {
sb.append('\'' + arrayOfKeys[i] + '\': ');
sb.append(String.valueOf(arrayOfValues[i]));
if(i!=arrayOfKeys.size() -1) {
sb.append(" , ");
}
}
sb.append("}");
return sb.toString();
}
public String toString() {
String results = "{";
for (int i = 0; i < arrayOfKeys.length; i++){
results += "'"+arrayOfKeys[i]+"' : "+arrayOfValue[i]+",";
}
results+="}";
return results;
}

Multiple string replacements without affecting substituted text in subsequent iterations

I've posted about letters earlier, but this is an another topic, I have a json response that contain 2 objects, from and to , from is what to change, and to is what it will be changed to .
My code is :
// for example, the EnteredText is "ab b test a b" .
EnteredString = EnteredText.getText().toString();
for (int i = 0; i < m_jArry.length(); i++) {
JSONObject jo_inside = m_jArry.getJSONObject(i);
String Original = jo_inside.getString("from");
String To = jo_inside.getString("to");
if(isMethodConvertingIn){
EnteredString = EnteredString.replace(" ","_");
EnteredString = EnteredString.replace(Original,To + " ");
} else {
EnteredString = EnteredString.replace("_"," ");
EnteredString = EnteredString.replace(To + " ", Original);
}
}
LoadingProgress.setVisibility(View.GONE);
SetResultText(EnteredString);
ShowResultCardView();
For example, the json response is :
{
"Response":[
{"from":"a","to":"bhduh"},{"from":"b","to":"eieja"},{"from":"tes","to":"neesj"}
]
}
String.replace() method won't work here, because first it will replace a to bhduh, then b to eieja, BUT here's the problem, it will convert b in bhduh to eieja, which i don't want to.
I want to perfectly convert the letters and "words" in the String according the Json, but that what i'm failing at .
New Code :
if(m_jArry.length() > 0){
HashMap<String, String> m_li;
EnteredString = EnteredText.getText().toString();
Log.i("TestAf_","Before Converting: " + EnteredString);
HashMap<String,String> replacements = new HashMap<String,String>();
for (int i = 0; i < m_jArry.length(); i++) {
JSONObject jo_inside = m_jArry.getJSONObject(i);
String Original = jo_inside.getString("from");
String To = jo_inside.getString("to");
if(isMethodConvertingIn){
//EnteredString = EnteredString.replace(" ","_");
replacements.put(Original,To);
Log.i("TestAf_","From: " + Original + " - To: " + To + " - Loop: " + i);
//EnteredString = EnteredString.replace(" ","_");
//EnteredString = EnteredString.replace(Original,To + " ");
} else {
EnteredString = EnteredString.replace("_"," ");
EnteredString = EnteredString.replace("'" + To + "'", Original);
}
}
Log.i("TestAf_","After Converting: " + replaceTokens(EnteredString,replacements));
// Replace Logic Here
// When Finish, Do :
LoadingProgress.setVisibility(View.GONE);
SetResultText(replaceTokens(EnteredString,replacements));
ShowResultCardView();
Output :
10-10 19:51:19.757 12113-12113/? I/TestAf_: Before Converting: ab a ba
10-10 19:51:19.757 12113-12113/? I/TestAf_: From: a - To: bhduh - Loop: 0
10-10 19:51:19.757 12113-12113/? I/TestAf_: From: b - To: eieja - Loop: 1
10-10 19:51:19.757 12113-12113/? I/TestAf_: From: o - To: neesj - Loop: 2
10-10 19:51:19.758 12113-12113/? I/TestAf_: After Converting: ab a ba
You question would be clearer if you gave the expected output for the function.
Assuming it is: ab b test a b >>>> bhduheieja eieja neesjt bhduh eieja
then see the following, the key point in the Javadoc being "This will not repeat"
http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/StringUtils.html#replaceEach(java.lang.String,%20java.lang.String[],%20java.lang.String[])
Replaces all occurrences of Strings within another String.
A null reference passed to this method is a no-op, or if any "search
string" or "string to replace" is null, that replace will be ignored.
This will not repeat. For repeating replaces, call the overloaded
method.
Example 1
import org.apache.commons.lang3.StringUtils;
public class StringReplacer {
public static void main(String[] args) {
String input = "ab b test a b";
String output = StringUtils.replaceEach(input, new String[] { "a", "b", "tes" },
new String[] { "bhduh", "eieja", "neesj" });
System.out.println(input + " >>>> " + output);
}
}
Example 2
import org.apache.commons.lang3.StringUtils;
public class StringReplacer {
public static void main(String[] args) {
String input = "this is a test string with foo";
String output = StringUtils.replaceEach(input, new String[] { "a", "foo" },
new String[] { "foo", "bar"});
System.out.println(input + " >>>> " + output);
}
}
Try following:
Solution 1:
Traverse the String characters one by one and move the new String to a new StringBuffer or StringBuilder, then call toString() to get the result. This will need you to implement string matching algorithm.
Solution 2 (Using Regex):
For this, you must know the domain of your string. For example, it is [a-zA-Z] then other arbitrary characters (not part of domain) can be used for intermediate step. First replace the actual characters with arbitrary one then arbitrary ones with the target. In example below, [!##] are the arbitrary characters. These can be any random \uxxxx value as well.
String input = "a-b-c";
String output = input.replaceAll("[a]", "!").replaceAll("[b]", "#").replaceAll("[c]", "#");
output = output.replaceAll("[!]", "bcd").replaceAll("[#]", "cde").replaceAll("[#]", "def");
System.out.println("input: " + input);
System.out.println("Expected: bcd-cde-def");
System.out.println("Actual: " + output);
Your issue is quite common. To sum things up :
String test = "this is a test string with foo";
System.out.println(test.replace("a", "foo").replace("foo", "bar"));
Gives : this is bar test string with bar
Expected by you : this is foo test string with bar
You can use StrSubstitutor from Apache Commons Lang
But first you will have to inject placeholders in your string :
String test = "this is a test string with foo";
Map<String, String> valuesMap = new HashMap<>();
valuesMap.put("a", "foo");
valuesMap.put("foo", "bar");
String testWithPlaceholder = test;
// Preparing the placeholders
for (String value : valuesMap.keySet())
{
testWithPlaceholder = testWithPlaceholder.replace(value, "${"+value+"}");
}
And then, use StrSubstitutor
System.out.println(StrSubstitutor.replace(testWithPlaceholder, valuesMap));
It gives : this is foo test string with bar
Here is an method which is strictly just Java. I tried not to use any Java 8 methods here.
public static String translate(final String str, List<String> from, List<String> to, int index) {
StringBuilder components = new StringBuilder();
String token, replace;
int p;
if (index < from.size()) {
token = from.get(index);
replace = to.get(index);
p = 0;
for (int i = str.indexOf(token, p); i != -1; i = str.indexOf(token, p)) {
if (i != p) {
components.append(translate(str.substring(p, i), from, to, index + 1));
}
components.append(replace);
p = i + token.length();
}
return components.append(translate(str.substring(p), from, to, index + 1)).toString();
}
return str;
}
public static String translate(final String str, List<String> from, List<String> to) {
if (null == str) {
return null;
}
return translate(str, from, to, 0);
}
Sample test program
public static void main(String []args) {
String EnteredString = "aa hjkyu batesh a";
List<String> from = new ArrayList<>(Arrays.asList("a", "b", "tes"));
List<String> to = new ArrayList<>(Arrays.asList("bhduh", "eieja", "neesj"));
System.out.println(translate(EnteredString, from, to));
}
Output:
bhduhbhduh hjkyu eiejabhduhneesjh bhduh
Explaination
The algorithm is recursive, and it simply does the following
If a pattern found in the string matches a pattern in the from list
if there is any string before that pattern, apply the algorithm to that string
replace the found pattern with the corresponding pattern in the to list
append the replacement to the new string
discard the pattern in the from list and repeat the algorithm for the rest of the string
Otherwise append the rest of the string to the new string
You could use split like:
String[] pieces = jsonResponse.split("},{");
then you just parse the from and to in each piece and apply them with replace() then put the string back together again. (and please get your capitalization of your variables/methods right - makes it very hard to read the way you have it)
Apache Commons StringUtils::replaceEach does this.
String[] froms = new String[] {"a", "b"};
String[] tos = new String[] {"b","c"};
String result = StringUtils.replaceEach("ab", froms, tos);
// result is "bc"
Why not keep it very simple (if the JSON is always in same format, EG: from the same system). Instead of replacing from with to, replace the entire markup:
replace "from":"*from*" with "from":"*to*"
Why not just change the actual "to" and "from" labels? That way, you don't run into a situation where "bhudh" becomes "eieja". Just do a string replace on "from" and "to".

Java equivalent of PHP's implode(',' , array_filter( array () ))

I often use this piece of code in PHP
$ordine['address'] = implode(', ', array_filter(array($cliente['cap'], $cliente['citta'], $cliente['provincia'])));
It clears empty strings and join them with a ",". If only one remains it doesn't add an extra unneeded comma. It doesn't add a comma at the end. If none remains it returns empty string.
Thus I can get one of the following results
""
"Street abc 14"
"Street abc 14, 00168"
"Street abc 14, 00168, Rome"
What is the best Java implementation (less code) in Java without having to add external libraries (designing for Android)?
Updated version using Java 8 (original at the end of post)
If you don't need to filter any elements you can use
String.join(CharSequence delimiter, CharSequence... elements)
String.join(" > ", new String[]{"foo", "bar"});
String.join(" > ", "foo", "bar");
or String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
String.join(" > ", Arrays.asList("foo", "bar"));
Since Java 8 we can use StringJoiner (instead of originally used StringBulder) and simplify our code.
Also to avoid recompiling " *" regex in each call of matches(" *") we can create separate Pattern which will hold its compiled version in some field and use it when needed.
private static final Pattern SPACES_OR_EMPTY = Pattern.compile(" *");
public static String implode(String separator, String... data) {
StringJoiner sb = new StringJoiner(separator);
for (String token : data) {
if (!SPACES_OR_EMPTY.matcher(token).matches()) {
sb.add(token);
}
}
return sb.toString();
}
With streams our code can look like.
private static final Predicate<String> IS_NOT_SPACES_ONLY =
Pattern.compile("^\\s*$").asPredicate().negate();
public static String implode(String delimiter, String... data) {
return Arrays.stream(data)
.filter(IS_NOT_SPACES_ONLY)
.collect(Collectors.joining(delimiter));
}
If we use streams we can filter elements which Predicate. In this case we want predicate to accept strings which are not only spaces - in other words string must contain non-whitespace character.
We can create such Predicate from Pattern. Predicate created this way will accept any strings which will contain substring which could be matched by regex (so if regex will look for "\\S" predicate will accept strings like "foo ", " foo bar ", "whatever", but will not accept " " nor " ").
So we can use
Pattern.compile("\\S").asPredicate();
or possibly little more descriptive, negation of strings which are only spaces, or empty
Pattern.compile("^\\s*$").asPredicate().negate();
Next when filter will remove all empty, or containing only spaces Strings we can collect rest of elements. Thanks to Collectors.joining we can decide which delimiter to use.
Original answer (before Java 8)
public static String implode(String separator, String... data) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.length - 1; i++) {
//data.length - 1 => to not add separator at the end
if (!data[i].matches(" *")) {//empty string are ""; " "; " "; and so on
sb.append(data[i]);
sb.append(separator);
}
}
sb.append(data[data.length - 1].trim());
return sb.toString();
}
You can use it like
System.out.println(implode(", ", "ab", " ", "abs"));
or
System.out.println(implode(", ", new String[] { "ab", " ", "abs" }));
Output ab, abs
Why so serious?
Try StringUtils.join(new String[] {"Hello", "World", "!"}, ", ") !
Here is an Android-specific answer that may be helpful to some:
String combined = TextUtils.join(",", new String[]{"Red", "Green", "Blue"});
// Result => Red,Green,Blue
Be sure to import the TextUtils class:
import android.text.TextUtils;
You'd have to add your strings to an ArrayList, remove empty ones, and format it accordingly:
public static String createAddressString( String street, String zip_code, String country) {
List<String> list = new ArrayList<String>();
list.add( street);
list.add( zip_code);
list.add( country);
// Remove all empty values
list.removeAll(Arrays.asList("", null));
// If this list is empty, it only contained blank values
if( list.isEmpty()) {
return "";
}
// Format the ArrayList as a string, similar to implode
StringBuilder builder = new StringBuilder();
builder.append( list.remove(0));
for( String s : list) {
builder.append( ", ");
builder.append( s);
}
return builder.toString();
}
Additionally, if you had String[], an array of strings, you can easily add them to an ArrayList:
String[] s;
List<String> list = new ArrayList<String>( Arrays.asList( s));
Using Streams (for Java 8 and later) would be an alternate possible solution for this.
You are required to import
java.util.stream.Collectors;
to use the join process
You may use:
Arrays.asList("foo","bar").stream().collect(Collectors.joining(","));
to achieve the desired result.
A simple Implode
public static String implode(String glue, String[] strArray)
{
String ret = "";
for(int i=0;i<strArray.length;i++)
{
ret += (i == strArray.length - 1) ? strArray[i] : strArray[i] + glue;
}
return ret;
}
You can create overloads for it..
The above it equivalent of php implode.
Here is what you want:
import java.lang.*
public static String customImplode(String glue, String[] strArray)
{
String ret = "";
for(int i=0;i<strArray.length;i++)
{
if (strArray[i].trim() != "")
ret += (i == strArray.length - 1) ? strArray[i] : strArray[i] + glue;
}
return ret;
}
Here's my implode implementation:
/**
* Implodes the specified items, gluing them using the specified glue replacing nulls with the specified
* null placeholder.
* #param glue The text to use between the specified items.
* #param nullPlaceholder The placeholder to use for items that are <code>null</code> value.
* #param items The items to implode.
* #return A <code>String</code> containing the items in their order, separated by the specified glue.
*/
public static final String implode(String glue, String nullPlaceholder, String ... items) {
StringBuilder sb = new StringBuilder();
for (String item : items) {
if (item != null) {
sb.append(item);
} else {
sb.append(nullPlaceholder);
}
sb.append(glue);
}
return sb.delete(sb.length() - glue.length(), sb.length()).toString();
}
public static String implode(List<String> items, String separator) {
if (items == null || items.isEmpty()) {
return null;
}
String delimiter = "";
StringBuilder builder = new StringBuilder();
for (String item : items) {
builder.append(delimiter).append(item);
delimiter = separator;
}
return builder.toString();
}
Use this simple function:
private String my_implode(String spacer, String[] in_array){
String res = "";
for (int i = 0 ; i < in_array.length ; i++) {
if (!res.equals("")) {
res += spacer;
}
res += in_array[i];
}
return res;
}
Use:
data_arr = {"d1", "d2", "d3"};
your_imploded_text = my_implode(",", data_arr);
// Output: your_imploded_text = "d1,d2,d3"

Java String Method

I have comma separated string variable like:
String doctors = "doc_vijayan,doc_zubair,doc_Raja"
But i want to delete "doc_" from the above String and First Letter should display in capital. I need output like this:
String doctors1 = "Vijayan, Zubair, Raja"
How to do that?
You can try that :
public String splitDoctors(String doctorsString){
String[] doctors = doctorsString.split(",");
boolean isFirst = true;
StringBuilder sb = new StringBuilder();
for(String doctor : doctors){
if(!isFirst){
sb.append(", ");
}else{
isFirst = false;
}
sb.append(doctor.substring(4,5).toUpperCase());
sb.append(doctor.substring(5));
}
return sb.toString();
}
Guava
With Guava, you can write something like this:
import com.google.common.base.*;
import com.google.common.collect.*;
//...
String doctors = "doc_vijayan,doc_zubair,doc_Raja";
Function<String,String> chopAndCap =
new Function<String,String>() {
#Override public String apply(String from) {
return from.substring(4, 5).toUpperCase()
+ from.substring(5);
}
};
Iterable<String> docs = Splitter.on(',').split(doctors);
docs = Iterables.transform(docs, chopAndCap);
doctors = Joiner.on(", ").join(docs);
System.out.println(doctors);
// Vijayan, Zubair, Raja
So the concrete logical steps are:
Define a Function to perform the chop-and-cap
Use Splitter to split into Iterable<String>
Iterables.transform each element using the above Function
Use Joiner to join from the transformed Iterable back to a String
If you're comfortable with this kind of programming style, you can just assemble the entire process into one smooth operation:
System.out.println(
Joiner.on(", ").join(
Iterables.transform(
Splitter.on(',').split(doctors),
new Function<String,String>() {
#Override public String apply(String from) {
return from.substring(4, 5).toUpperCase()
+ from.substring(5);
}
}
)
)
);
// Vijayan, Zubair, Raja
Apache Commons Lang
With Apache Commons Lang, you can write something like this:
import org.apache.commons.lang.*;
//...
String doctors = "doc_vijayan,doc_zubair,doc_Raja";
String[] docs = StringUtils.split(doctors, ',');
for (int i = 0; i < docs.length; i++) {
docs[i] = StringUtils.capitalize(
StringUtils.substringAfter(docs[i], "doc_")
);
}
doctors = StringUtils.join(docs, ", ");
System.out.println(doctors);
// Vijayan, Zubair, Raja
Note that you if you have both Guava and Apache Commons Lang, you can use StringUtils.capitalize/substringAfter in chopAndCap function above.
final String[] docs = doctors.split(",");
final StringBuilder sb = new StringBuilder();
for (final String d : docs) {
String doct = d.replace("doc_", "");
doct = doct.subString(0,1).toUpperCase() + doct.subString(1).toLowerCase();
sb.append(sb.length() > 0 ? ", " : "");
sb.append(doct);
} // you should be able to do the rest.
String regex = "doc_.";
Matcher matcher = Pattern.compile(regex).matcher(doctors);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String group = matcher.group();
int i = group.length() - 1;
matcher.appendReplacement(sb, String.valueOf(group.charAt(i)).toUpperCase());
}
matcher.appendTail(sb);
System.out.print(sb.toString());
The easiest way is to use 'any' StringUtils library out there. For example org.apache.commons.lang.StringUtils has a chomp and a capitalize method which should bring you a long way.

Categories

Resources