I am having a string of the form as
PosAttributes: FN,CT,ST;
Now when i compute some functionality i get a string as
PosAttributes1: FN,ST,CT;
Now though both the strings suggest the same thing and if use following equal function it returns false. I know both stings are not same, but the semantics are same. What should i do?
PosAttributes.equals(PosAttributes);
As the string is delimitered by commas you could use a String.split to give
String arr[] = PosAttributes.split (",");
String arr2[] = PosAttributes1.split (",");
then you just need to loop through the first arrays ensuring that ALL elements are in the second array. Also check that the sizes are identical.
You need to break out the individual sections of each String, and store them in some kind of Set - that's a structure where either there's no order, or where the order doesn't affect the outcome of the equals method. I'd write a method like this.
private static Set<String> attributeSet(String input) {
String[] attributes = input.split(",");
return new HashSet<String>(Arrays.asList(attributes));
}
This breaks a String into its segments, assuming the separator is a comma. Then it uses a standard trick to convert the resulting array into a HashSet, which is a commonly used type of Set.
Then when I want to compare two strings, I could write something like
if (attributeSet(string1).equals(attributeSet(string2))) {
// ...
}
So assuming that the example text is the full text, you need to remove the ; character, as this would change the contents of the String, split the String on the , character, sort the resulting arrays and compare them, something like...
String[] v1 = "FN,CT,ST;".replace(";", "").split(",");
String[] v2 = "FN,ST,CT;".replace(";", "").split(",");
Arrays.sort(v1);
Arrays.sort(v2);
System.out.println(Arrays.equals(v1, v2));
Which outputs true
What I might be tempted to do is write a method which returned a sorted array of the String, replicating all the common functionality...
public static String[] sorted(String value) {
String[] v1 = value.replace(";", "").split(",");
Arrays.sort(v1);
return v1;
}
And then you could simply call it, which would allow you to do a single like comparison...
System.out.println(Arrays.equals(sorted("FN,CT,ST;"), sorted("FN,ST,CT;")));
The next step might be to write a method which returns true, which called sorted and Arrays.equals to make it easier...
System.out.println(isEqual("FN,CT,ST;", "FN,ST,CT;"));
But, I'll leave that up to you ;)
You can either override the equal method or sort both string then compare them.
I have the same requirement at work right now and wanted to avoid using lists for the evaluation.
What I did was to check if the two string to compare are of equal length - this means that it is possible that they might be the same, just with different order.
Now remove one by one comma-separated string in the main string, found in the compare string. If the output of the main string is empty, that means the two are an exact math. Please see the pseudo-code below (I did not paste the actual code because it has some company specific info):
private static boolean isStringCombinationEqual(final String main, final String compare)
{
boolean result = false;
String modifiedMain = main;
// if not the same length, then cannot possibly be same combination in different order
if (main.length() == compare.length())
{
final String[] compareArr = // split compare using delimiter
for (int i = 0; i < compareArr.length; i++)
{
if (i > 0)
{
modifiedMain = // replace delimiter with empty string
}
modifiedMain = // replace compareArr[0] with empty string
}
if (//modifiedMain is empty)
{
result = true;
}
}
return result;
}
Related
Good morning! I received a problem statement to write a method that returns all possible combinations of a String input passed, e.g.
if ABC is passed then it returns [A, AB, BC, ABC, AC, B, C]
if ABCD is passed then it returns [A, AB, BC, CD, ABC, AC, ACD, B, BCD, BD, ABD, AD, C, D, ABCD]
means AB and BA are always taken same, ABC, BAC and ACB are also same.
I ended up writing below code and it seems to working though (not sure).
public static Set<String> getAnyPermutations(String s,String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for(int i=0; i<inp.length; i++) {
String temp =s+String.valueOf(inp[i]);
resultSet.add(temp);
if(i+1<=inp.length)
resultSet.addAll(getAnyPermutations(temp, String.valueOf(Arrays.copyOfRange(inp, i+1, inp.length))));
}
return resultSet;
}
My question is, I want to remove the first param(String s) from the method as using it for interal comutations only, or if that is not possible then making sure that user always pass a "" value or I can reset it to "" for the first(non-recursive) call of this method. I am going confused how to do that inside a recursive funtion.
Also please add comment if you have doubt it can fail other than this situation.
Conditions, All has to be done inside this function only, no other method can be created.
All has to be done inside this function only, no other function can be created.
Then you can't do it. The function has no (reasonable)* way of knowing whether it called itself or was called by another function.
There are lots of solutions involving creating another function. One that might fit your requirements, depending on how they're actually expressed, would be to have the function define a lambda to do the work, and have the lambda call itself. E.g., getAnyPermutations wouldn't actually be recursive, it would contain a recursive function.
But that may be out of bounds depending on the exact meaning of the quote above, since the lambda is another function, just not one that can be accessed from the outside.
* The unreasonable way is by examining a stack trace, which you can get from Thread.currentThread().getStackTrace.
You can always transform a recursive method into its iterative equivalent - e.g. see
Way to go from recursion to iteration.
In the iterative version it's easy to not expose the state parameter (you now just need to initialize it at the beginning of the iterative method).
This is not very practical in general (but I believe that the purpose of the question is more theoretical, otherwise it's always a good solution to just expose another method).
Furthermore, in this particular situation you might consider this simple iterative approach (though it is not obtained by directly translating the given code):
public static Set<String> getAnyPermutations(String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for (int bitMask = 0; bitMask < (1 << inp.length); bitMask++) {
StringBuilder str = new StringBuilder();
for (int i = 0; i < inp.length; i++) {
if ((bitMask & (1 << i)) != 0) {
str.append(inp[i]);
}
}
if (str.length() > 0) {
resultSet.add(str.toString());
}
}
return resultSet;
}
You can change the current method to be a private one and interface it with a public method with one argument e.g.:
private static Set<String> getAnyPermutations(String s,String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for(int i=0; i<inp.length; i++){
String temp =s+String.valueOf(inp[i]);
resultSet.add(temp);
if(i+1<=inp.length)
resultSet.addAll(getAnyPermutations(temp, String.valueOf(Arrays.copyOfRange(inp, i+1, inp.length))));
}
return resultSet;
}
Now, you can expose a one argument method to the user which in turn will call the above method, e.g.:
public static Set<String> getAnyPermutations(String strInput) {
return getAnyPermutations("", strInput);
}
Update
If you can't create any other method at all then the only alternative would be to use var-args. However, that requires change in the implementation and doesn't actually restrict the user from passing multiple values.
You can rewrite this particular algorithm so that it doesn't need to carry a state through to the recursively called invocation.
(Java-centric pseudocode):
Set<String> getAnyPermutations(String str) {
if(str.length() == 0) {
return Collections.emptySet();
}
String head = str.substring(0,1);
String tail = str.substring(1);
Set<String> permutationsOfTail = getAnyPermutations(tail);
Set<String> result = new HashSet();
// Head on its own
// For input 'ABC', adds 'A'
result.add(head);
// All permutations that do not contain head
// For input 'ABC', adds 'B', 'C', 'BC'
result.addAll(permutationsOfTail);
// All permutations that contain head along with some other elements
// For input 'ABC', adds 'AB, 'AC', 'ABC'
for(String tailPerm : permutationsOfTail) {
result.add(head + tailPerm);
}
return result;
}
This meets your aim of not creating any extra methods -- but note that it would be cleaner code if the for loop was extracted into a new method Set<String> prefixEachMember(String prefix, Set<String> strings) allowing result.addAll(prefixEachMember(head,permutationsOfTail)).
However it's not always possible to do this, and sometimes you do want to carry state. One way is the way you've asked to avoid, but I'm going to include it in my answer because it's a clean and common way of achieving the aim.
public Foo myMethod(Bar input) {
return myMethod(new HashSet<Baz>(), input);
}
private Foo myMethod(Set<Baz> state, Bar input) {
if(...) {
return ...;
} else {
...
return myMethod(..., ...);
}
}
Here, the first method is your public API, in which the collector/state parameter is not required. The second method is a private worker method, which you initially call with an empty state object.
Another option is to refer to an object field. I would recommend against this, however, because it gets confusing when recursive code refers to a global object.
Suppose I have a string String s = "0123456789t:9876543210"
How can I get the index immediately following "t:" (i.e, index 12)?
Is there a built-in way, or am I stuck with s.substring(s.indexOf("t:")+2); ?
Specifically, I'm wanting a solution for any token-length. So my token may be t:, or it may as easily be test:. Regardless of the token itself, is there a way to dynamically get the index immediately following whatever token I search on?
This is the correct way of finding index.
int indexOf(String str)
From Javadocs,
Returns the index within this string of the first occurrence of the
specified substring. The integer returned is the smallest value k such
that:
this.startsWith(str, k)
To make it dynamic, pls have a structure of this sort.
public static void main(String[] args) {
String s = "0123456789t:9876543210";
System.out.println(getIndex("t:", s));
s = s.substring(s.indexOf("t:") + 2);
System.out.println(s);
}
private static int getIndex(String searchedText, String inputText) {
return inputText.indexOf(searchedText) + searchedText.length();
}
output
12
9876543210
You can use IndexOf like this:
s.indexOf(s + ":")+2
Why not just make it all modular having an arraylist of strings, with all commands and for it you can do:
ArrayList<String> al = new ArrayList<String>();
String s = "123456789t:987654321";
al.add("t:");//this is where you add your cases
for(String c:al){
System.out.println(s.substring(s.indexOf(c) + c.length));
}
that way the length of the case cant be messed up b/c it is part of the string class
I have a string which contains an underscore as shown below:
123445_Lisick
I want to remove all the characters from the String after the underscore. I have tried the code below, it's working, but is there any other way to do this, as I need to put this logic inside a for loop to extract elements from an ArrayList.
public class Test {
public static void main(String args[]) throws Exception {
String str = "123445_Lisick";
int a = str.indexOf("_");
String modfiedstr = str.substring(0, a);
System.out.println(modfiedstr);
}
}
Another way is to use the split method.
String str = "123445_Lisick";
String[] parts = string.split("_");
String modfiedstr = parts[0];
I don't think that really buys you anything though. There's really nothing wrong with the method you're using.
Your method is fine. Though not explicitly stated in the API documentation, I feel it's safe to assume that indexOf(char) will run in O(n) time. Since your string is unordered and you don't know the location of the underscore apriori, you cannot avoid this linear search time. Once you have completed the search, extraction of the substring will be needed for future processing. It's generally safe to assume the for simple operations like this in a language which is reasonably well refined the library functions will have been optimized.
Note however, that you are making an implicit assumption that
an underscore will exist within the String
if there are more than one underscore in the string, all but the first should be included in the output
If either of these assumptions will not always hold, you will need to make adjustments to handle those situations. In either case, you should at least defensively check for a -1 returned from indexAt(char) indicating that '_' is not in the string. Assuming in this situation the entire String is desired, you could use something like this:
public static String stringAfter(String source, char delim) {
if(source == null) return null;
int index = source.indexOf(delim);
return (index >= 0)?source.substring(index):source;
}
You could also use something like that:
public class Main {
public static void main(String[] args) {
String str = "123445_Lisick";
Pattern pattern = Pattern.compile("^([^_]*).*");
Matcher matcher = pattern.matcher(str);
String modfiedstr = null;
if (matcher.find()) {
modfiedstr = matcher.group(1);
}
System.out.println(modfiedstr);
}
}
The regex groups a pattern from the start of the input string until a character that is not _ is found.
However as #Bill the lizard wrote, i don't think that there is anything wrong with the method you do it now. I would do it the same way you did it.
I am simply trying to see if the inputted value matches a value that is already in the array and if it does return "Valid". I realize this is very simple but I cannot get this to work:
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
String[] accountNums = { "5658845", "8080152", "1005231", "4520125", "4562555",
"6545231", "7895122", "5552012", "3852085", "8777541",
"5050552", "7576651", "8451277", "7881200", "1302850",
"1250255", "4581002" };
String newAccount;
String test = "Invalid";
newAccount = keyboard.next();
for (int i = 0; i < accountNums.length; i++)
{
if(newAccount == accountNums[i])
{
test = "Valid";
}
}
System.out.println(test);
}
}
thank you for any assistance (and patience)
Use equals method. Check here why to.
if (newAccount.equals(accountNums[i]))
Jayamohan's answer is correct and working but I suggest working with integers rather than Strings. It is a more effective approach as CPUs handle numbers (integers) with a lot more ease than they handle Strings.
What has to be done in this case is change newAccount and accountNums to ints instead of Strings and also remove all the quotation marks from the accountNums initialization. Instead of calling keyboard.next() you can call keyboard.nextInt(), which returns an integer. The if-statement is fine as it is.
Why are you using an array?
List<String> accountNums = Arrays.asList( "5658845", "8080152", "1005231", "4520125", "4562555",
"6545231", "7895122", "5552012", "3852085", "8777541",
"5050552", "7576651", "8451277", "7881200", "1302850",
"1250255", "4581002" );
String test = "Invalid";
Then you just need this (no loop):
if (accountNums.contains(newAccount)) {
test = "Valid";
}
Plus, it's easier to read and understand.
You cannot compare strings with ==
You must use .equals()
I wrote a recursive method that gets all possible character combinations from the characters in a string. I also have a method to access it and return a list of the combos:
public static void uns(String word, StringBuilder s, List combos)
{
for(char c: word.toCharArray())
{
s.append(c);
if(word.length() != 1)
{
uns(removeChar(word, c),s,combos);
}
else
{
combos.add(s.toString());
}
s.deleteCharAt(s.toString().length()-1);
}
}
public static List getCombinations(String word)
{
List<String> combinations = new ArrayList<String>();
uns(word,new StringBuilder(),combinations);
return combinations;
}
public static String removeChar(String s, char c)
{
int index = s.indexOf(c);
return s.substring(0,index)+s.substring(index+1);
}
When testing it in Java, it ran with no flaws. For some reason, when I use it in Android, the list is populated with the correct number of elements, but every element is the same. For instance, for the word "here", it returns a list filled with "eerh".
This is a very weird glitch (definitely reproducible) and you may want to file a bug report on this.
However, here is a temporary workaround; instead of using .toString(), which appears to somehow reuse the reference (even if I do .substring(0) with it), so all of them get updated; if you print out the list after each iteration, you'll see what I mean.
Here is my hacky/inefficient solution. Change:
combos.add(s.toString());
... to:
combos.add(s + "");
This effectively clones the string properly into the array, so that they are not manipulated:
02-17 19:33:48.605: I/System.out(6502): [Combos]: [here, heer, hree, hree, here, heer, ehre, eher, erhe, ereh, eehr, eerh, rhee, rhee, rehe, reeh, rehe, reeh, ehre, eher, erhe, ereh, eehr, eerh]
I'm not positive but i think the valueOf() method from the string class will work also. maybe try using a List instead of the StringBuilder, add characters to the list and try String.valueOf(s.get(i)); and that should convert the character to a string. i don't see why out wouldn't work in Android but you may need to modify your loop a little. hope that helps.