My java program formats data from a string array into a string and can basically pull an inception and store these strings along other strings of the same format, in a way making a 2D array but in a string format. My issue is for a 1D array I roughly have the following methods in a class...
public static String parse(String data) {
return "#"+Integer.toString(data.length())+":"+data;
}
public static String parse(String[] data) {
String str="";
for (int i=1;i<=data.length;i++) {
str+=parse(data[i-1]);//parse() would receive a String
}
return str;
}
My problem is I want to make a singular method that can take in an array of ANY dimensions, but the closest I can get to doing this is declaring multiple methods with the same name but with higher array dimensions set for the input variable 'data' like so...
public static String parse(String[][] data) {//can take in a 2D array
String str="";
for (int i=1;i<=data.length;i++) {
str+=parse(data[i-1]);//parse() would receive a 1D array
}
return str;
}
public static String parse(String[][][] data) {//can take in a 3D array
String str="";
for (int i=1;i<=data.length;i++) {
str+=parse(data[i-1]);//parse() would receive a 2D array
}
return str;
}
//etc...
Is there a way to work arround this? Or is this the best way to program it?
PS:I'm new to this language and still dont know a lot of terminology, so keep it simple please.
The problem is the difference in types, 1 parse method takes a String[][][] and calls another parse method that takes a String[][]. That second call is different for each level, so you can't create 1 single method that works for all of them.
Something that you can do (but will be tricky to grasp for a beginner) is reduce some of the duplication. If you pass the next parse method to call as an argument to parse. You can then use lambdas to chain method calls together:
public static String parse0(String data) {
return "#" + Integer.toString(data.length()) + ":" + data;
}
// Method that contains the real logic
private static <T> String parseInternal(T[] data, Function<T, String> parser) {
String str = "";
for (int i = 0; i < data.length; i++) {
str += parser.apply(data[i]);
}
return str;
}
// Methods that provide the call chain:
public static String parse3(String[][][] data) {
return parseInternal(data, arr2 -> parse2(arr2));
}
public static String parse2(String[][] data) {
return parseInternal(data, arr -> parse1(arr));
}
public static String parse1(String[] data) {
return parseInternal(data, str -> parse0(str));
}
Note: I gave all the methods a different name to show better what is going on. But you could give all of them the same name as well.
For more information about lambda expressions see the Oracle tutorial.
The solution is called recursion: that a method sometimes calls itself for doing some of its task:
public static String parse(Object data) {
if (data instanceof String) {
return "#" + Integer.toString(((String) data).length()) + ":" + data;
}
if (data instanceof Object[]) {
String str = "";
for (Object obj : (Object[]) data) {
str += parse(obj);
}
return str;
}
throw new IllegalArgumentException("Cannot parse type " + data.getClass());
}
Now we may do for instance:
System.out.println(parse("str"));
System.out.println(parse(new String[] { "abc", "def" }));
System.out.println(parse(new String[][] { { "gh", "ij" }, { "kl" } }));
System.out.println(parse(new String[][][] { { { "mn" }, { "op", "qr", "st" }, { "uv" } } }));
This prints:
#3:str
#3:abc#3:def
#2:gh#2:ij#2:kl
#2:mn#2:op#2:qr#2:st#2:uv
In fact you can call it with a String array with any number of dimension.
Related
I am trying to solve a question where I need to remove specific substring from string using recursion.
I was able to solve this using a do while loop but that is not the best approach.
For example,
Suppose I have a string named, DADDAUUPPA and if I am given set of substrings like "DD", "UU","PP", "AA" then the returned string should be DA because, DADDAUUPPA -> DAAUUPPA -> DUUPPA -> DPPA -> DA
Here is my solution doing it using while loop.
String s = "DADDAUUPPA";
do{
String original = s;
return original.replace("DD","").replace("UU","").replace("PP","").replace("AA","" );
} while(!original)
Other challenging task is what if we are given these substrings as an array, how would we do it then?
For example,
public soln (String[] sub) {
// sub contains all the substring to be removed
}
Here is a solution
import java.util.LinkedList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> subs = new LinkedList<>();
subs.add("DD");
subs.add("AA");
subs.add("UU");
subs.add("PP");
String result = getSubString(subs, "DADDAUUPPA ");
System.out.print(result);
}
private static String getSubString(List<String> subs, String myString) {
if(subs !=null && subs.size() != 0) {
String sub = subs.get(0);
subs.remove(0);
myString = getSubString(subs, myString.replace(sub, ""));
}
return myString;
}
}
Key thing to learn is
private static String getSubString(List<String> subs, String myString) {
if(subs !=null && subs.size() != 0) {
myString = myString.replace(subs.get(0), "");
subs.remove(0);
getSubString(subs, myString);
}
return myString;
}
This does not work, note the difference between first and second getSubString method. As the stack unwinds myString gets assigned to original value.
Is it possible to get substring from right hand hand(Reverse) direction using substring() in JAVA.
Example.
Suppose String S="abcdef",
Can I get Substring "fedc" using S.substring(S.length()-1,3) ?
If it is not correct, please suggest me how to get Substring from right hand end(Reverse direction)??
You could reverse the string and use substring. Unfortunately String does not have that, but StringBuilder has it e.g.
new StringBuilder("abcdef").reverse().toString().substring(0,4);
You can reverse the string and find the substring
// reverse
String s = "abcdef";
StringBuilder builder = new StringBuilder(s);
String substring = builder.reverse().substring(0,3);
Java doesn't support extension methods like C# does, so I would build a function for this. This way you can control how much of the reverse substring you want with a parameter.
public class StackOverflow {
public static void main(String[] args) {
String data = "abcdef";
for (int i = 0; i < data.length(); i++) {
System.out.println(reverseSubstring(data, i+1));
}
}
public static String reverseSubstring(String data, int length) {
return new StringBuilder(data).reverse().substring(0, length);
}
}
Result:
f
fe
fed
fedc
fedcb
fedcba
UPDATE
Another approach is to create a wrapper class to String. This way you can call a class method like how you're asking in your question with the example S.substring(S.length()-1,3). This will also allow you to still have all the String methods after using the wrapper's get() method.
String Wrapper
public class MyString {
private String theString;
public MyString(String s) {
theString = s;
}
public String get() {
return theString;
}
public String reverseSubstring(int length) {
return new StringBuilder(theString).reverse().substring(0, length);
}
}
Usage
public class StackOverflow {
public static void main(String[] args) {
MyString data = new MyString("abcdef");
for (int i = 0; i < data.get().length(); i++) {
System.out.println(data.reverseSubstring(i+1));
}
}
}
Results:
f
fe
fed
fedc
fedcb
fedcba
I am busy with a project that extracts data from a xml file and displays it in a word document. I have created a method for this extraction, but I want to simplify it by using an array of methods.
This is just an example of how I test for certain information at the moment:
for (int i = 0; i < nodeMap.getLength(); i++) {
Node node = nodeMap.item(i);
if (node.getNodeName().equalsIgnoreCase("maximumRedeliveries")) {
if (node.getNodeValue().startsWith("{{")) {
retryLogic.setMaximumRedeliveries(extractPropertyName(node.getNodeValue(), propFileLocation));
} else {
retryLogic.setMaximumRedeliveries(node.getNodeValue());
}
}
if (node.getNodeName().equalsIgnoreCase("asyncDelayedRedelivery")) {
if (node.getNodeValue().startsWith("{{")) {
retryLogic.setAsyncDelayedRedelivery(extractPropertyName(node.getNodeValue(), propFileLocation));
} else {
retryLogic.setAsyncDelayedRedelivery(node.getNodeValue());
}
}
}
I am aiming to create an array for the if statement values, for example "maximumRedeliveries" and "asyncDelayedRedelivery" and an array for their corresponding methods, for example setMaximumRedeliveries(),setAsyncDelayedRedelivery(). I am unsure of how to create an array of methods, or if it's even possible?
This problem differs form Java - Creating an array of methods, because I use set methods and don't know how to implement it in that way.
First, ensure that extractPropertyName takes names with and without curly braces, and behaves like this:
String extractOptionalPropertyName(String name, String propFileLocation) {
return name..startsWith("{{") ? extractPropertyName(name, propFileLocation) : name;
}
This moves conditionals from your XML processing code into a helper:
String nodeName = node.getNodeName();
if (nodeName.equalsIgnoreCase("maximumRedeliveries")) {
retryLogic.setMaximumRedeliveries(extractOptionalPropertyName(node.getNodeValue(), propFileLocation));
} else if (nodeName.equalsIgnoreCase("asyncDelayedRedelivery")) {
retryLogic.setAsyncDelayedRedelivery(extractOptionalPropertyName(node.getNodeValue(), propFileLocation));
} ... // and so on
With these changes in place, you can follow the recipe from this other Q&A and make a Map<String,ValSetter> objects, like this:
interface ValSetter {
void set(RetryLogic logic, String val);
}
// The map can be made static in a class
Map<String,ValSetter> setterForName = new HashMap<>();
{ // Initializer block
setterForName.put("maximumredeliveries", new ValSetter() {public void set(RetryLogic logic, String val) { logic.setMaximumRedeliveries(val);}} );
setterForName.put("asyncrelayedredelivery", new ValSetter() {public void set(RetryLogic logic, String val) { logic.setAsyncDelayedRedelivery(val);}} );
}
Now your XML handler could look like this:
String nodeName = node.getNodeName();
ValSetter setter = setterForName.get(nodeName.toLowerCase());
if (setter != null) {
String val = extractOptionalPropertyName(node.getNodeValue(), propFileLocation);
setter.set(retryLogic, val);
} else {
// report an error
}
How do you return an array object in Java? I have an object that has an array in it and I want to work with it in my main class:
// code that does not work
class obj()
{
String[] name;
public obj()
{
name = new string[3];
for (int i = 0; i < 3; i++)
{
name[i] = scan.nextLine();
}
}
public String[] getName()
{
return name;
}
}
public class maincl
{
public static void main (String[] args)
{
obj one = new obj();
system.out.println(one.getName());
}
I am sorry if the answer is simple but I am teaching myself to code and I have no idea how you would do this.
You have to use the toString method.
System.out.println(Arrays.toString(one.getName()));
toString is a built-in function in Java (it might need library import; if you are using Netbeans, it will suggest it).
If the problem is to print it use
System.out.println(Arrays.toString(one.getName()));
//note System, not system
When you do getName() you are returning a reference to an array of strings, not the strings themselves. In order to access the individual strings entered, you can use the array index
String enteredName = name[index] format.
From your program, it looks like you want to print each item entered. For that, you could use a method like the following
public void printName() {
// for each item in the list of time
for(String enteredName : name) {
// print that entry
System.out.println(enteredName);
}
}
Hello
Why my reverse method that uses recursion isn't working?
The print statement shows that the operation is done correctly but at the end it seems like only the very ast char of the entire String is assigned to h.
public static String reverse(String s,String h){
if(s.length()==0){
return s;
} else {
h+=s.charAt(s.length()-1);
System.out.println(h);//FOR TEST
s=s.substring(0,s.length()-1);
reverse(s,h);
return h;
}
}
Any advice?
Use
return reverse(s,h);
instead of
return h;
i.e:
public static String reverse(String s,String h){
if(s.length() == 0){
return h;
} else {
h+=s.charAt(s.length()-1);
System.out.println(h);//FOR TEST
s=s.substring(0,s.length()-1);
return reverse(s,h); //NOTICE THE CHANGE HERE,
}
}
Strings in Java are immutable. So in this code:
private static void foo(String x) {
x += "bar";
}
public static void main() {
String a = "foo";
foo(a);
System.out.println(a);
}
Only "foo" will be printed. It works the same way as if the type were int.
So your reverse function needs to do something with the return value. When you call reverse(s,h) you are throwing away the return value from the recursive call. You need to incorporate it:
String rec = reverse(s,h);
return ... something involving rec ...;
2 things:
public static String reverse(String s,String h){
if(s.length()==0){
return h; /// This needs to return the reversed string (h).
} else {
h+=s.charAt(s.length()-1);
System.out.println(h);//FOR TEST
s=s.substring(0,s.length()-1);
h = reverse(s,h); /// You need to use the return value
return h;
}
}
It looks like you were trying to change h using a return-by-reference-parameter. You have to remember that in Java everything (including references to objects) is passed by value. Once you write s=s.substring(0,s.length()-1);, s becomes a reference to a different String object, and that change is not propagated to the calling function.
Also, there is a way to implement this with only one input parameter.
I think this way is better for reversing a string using a recursive method :
public class Reversestringbyrecursivefunction {
public static void main(String[] args)
{
Scanner input=new Scanner(System.in);
while(true)
{
System.out.print("[?] Enter String('q' for exit)> ");
String str=input.next();
if(str.equals("q"))
break;
System.out.println("this string created by reversed recursive function : "+revers(str));
System.out.print("\n==========================\n");
}
System.out.print("\n\n\t\t\t[ GOOD LUCK!!! ]\n");
}
static String revers(String str)
{
if(str.length()<=1)
return str;
else
return revers(str.substring(str.length()-1, str.length()))+revers(str.substring(0, str.length()-1));
}
}
but , for best performance you should change this line :
return revers(str.substring(str.length()-1, str.length()))+revers(str.substring(0, str.length()-1));
to :
return str.substring(str.length()-1)+revers(str.substring(1, str.length()-1)+str.substring(0,1);
in prior line: in best performance and in one stage you can swap only 1 character of input string . but , in new line: in one stage you can swap 2 character of input string