All combinations of alphanumeric string, better way? - java

The input to the "alphaNumeric" function is a String which consists of alphanumeric characters that are all lower case, for example "hello123hello". I want to be able to check all upper/lower case letter combinations for this string through a check( ) function. (Eg. HeLlO123hELlo is one of the combinations to be checked). I have written code in Java to do this where I store the matching String into an ArrayList, but would like to know if there a better way to do this without the ArrayList. Also, am I correct in saying the worst case runtime of this is O(2^n)? Note: Check is a function that returns either true or false, depending on whether the correct String is passed to the function.
public static String alphaNumeric(String input) {
ArrayList<String> list = new ArrayList<String>();
alphaHelper(input, "", list);
return list.get(0);
}
private static void alphaHelper(String in, String current, ArrayList<String> list) {
if (in.length() == 0) {
if (check(current)) {
list.add(current);
}
} else if (Character.isLetter(in.charAt(0))) {
alphaHelper(in.substring(1),current+in.substring(0,1).toLowerCase(),list);
alphaHelper(in.substring(1),current+in.substring(0,1).toUpperCase(),list);
} else if (Character.isDigit(in.charAt(0))) {
alphaHelper(in.substring(1),current+in.substring(0,1),list);
} else {
return;
}
}

If you just want to remove the ArrayList without changing your basic algorithm, you can do this:
public static String alphaNumeric(String input) {
return alphaHelper(input, "");
}
private static String alphaHelper(String in, String current) {
String result = null;
if (check(current)) {
result = current;
} else if (Character.isLetter(in.charAt(0))) {
result = alphaHelper(in.substring(1),current+in.substring(0,1).toLowerCase());
if (result == null) result = alphaHelper(in.substring(1),current+in.substring(0,1).toUpperCase());
} else if (Character.isDigit(in.charAt(0))) {
result = alphaHelper(in.substring(1),current+in.substring(0,1));
}
return result;
}
Yes it is O(2^n), and I can't see offhand how you would improve on that if you can't get the original string directly.
If you don't need to check substrings (i.e. you only care about case variations of the entire string) you could improve the algorithm by not testing the substrings, but it would still be O(2^n).

You could temporarily set both the check and input to lowercase and compare them then.
public static boolean alphaNumeric(String input, String check) {
return input.toLowerCase().equals(check.toLowerCase());
}
-Sean

Related

Is there a way to merge this 2?

I'm running out of idea of how will I merge this 2 conditions, it has the same return so I need to merge
if ((StringUtils.isBlank(ext))) {
return true;
}
for (String str : INVALID_EXTENSION_ARR) {
if (ext.matches(str)) {
return true;
} else if (ext.matches(str.toLowerCase())) {
return true;
}
}
You don't need a loop.
Populate INVALID_EXTENSION_ARR with values in lowercase:
private static final List<String> INVALID_EXTENSION_ARR = Arrays.asList("foo", "bar", "whatever"); // Note: All in lowercase!
Then it's just one line:
return StringUtils.isBlank(ext) || INVALID_EXTENSION_ARR.contains(ext.toLowerCase());
Note: I have assumed when you used matches() you meant to use equals().
——-
If the list of acceptable extensions is “large” (say, more than 10), you’ll get better performance if you use a Set instead of a List:
private static final Set<String> INVALID_EXTENSION_ARR = new HashSet<>(Arrays.asList("foo", "bar", "whatever"));
Or for recent java versions:
private static final Set<String> INVALID_EXTENSION_ARR = Set.of("foo", "bar", "whatever");
But you would be unlikely to notice much difference unless the size was more than say 100.
Assuming that the loop will always be entered into,
for (String str : INVALID_EXTENSION_ARR) {
if (StringUtils.isBlank(ext) || ext.matches(str)) {
return true;
} else if (ext.matches(str.toLowerCase())) {
return true;
}
}
but I think that way that had it was easier to read and does not need to re-evaluate StringUtils.isBlank(ext) every time.
It is helpful if you provide more context, but this is one of the ways you can compact it.
for (String str : INVALID_EXTENSION_ARR) {
if (StringUtils.isBlank(ext) || ext.toLowerCase().matches(str.toLowerCase())) {
return true;
}
}

Using regex with sets in Java

I have a set in Java with different strings, such as '+Cat', '+Dog', etc. I also have a string as shown below.
animals = '+Cat|+Dog|+Goat'
Basically, if the set contains any of the animals listed in animals, I want to return false. How would I go about doing this? I am not sure if you can use regex with contains. Furthermore the fact that I have the + in my string complicates regex.
public boolean containCheck(Set<String> newset) {
String animals = "+Cat|+Dog|+Goat";
for (String op : animals.split("\\|")) {
if (newset.contains(op)) {
return false;
}
}
return true;
}
You can split the string in array and use a for loop to check it the set contains any element presents in the array.
public Boolean isContaining(String animals, Set<String> sets ) {
for (String s : animals.split("\\|")) {
for (String set : sets) {
if (s.equals(set)) {
return false;
}
}
}
return true;
}

How to use IndexOf to see if a string contain numbers

I need to use indexOf to find numbers inside a string, and it gives me the error:
Type mismatch: cannot convert from int to boolean.
public static boolean validPassword(String password) {
if(password.length() >= 8 ){
return true;
}
else if (password.indexOf("0")) {
return true;
}
return false;
}
Don't use index. You can use String.matches().
String str = "ksksks8ksksksksksks";
System.out.println(str.matches(".*\\d.*"));
Honestly though, if you can do it anyway you want, I would simply write a method as follows. Regular expressions are great for complicated patterns but they are also expensive in terms of processing.
public static boolean containsNumber(String str) {
boolean found = false;
for (char c : str.toCharArray()) {
if (Character.isDigit(c)) {
found = true;
break;
}
}
return found;
}
You could also modify the above and call it indexOf and iterate thru the characters using a regular for loop. Then returning either the location of the first digit or -1 just like the String version of indexOf().
And finally, for fun, you could use the Streams capability of Java 8+.
public static boolean containsNumber(String str) {
return str.chars().filter(Character::isDigit).count() > 0;
}

Find unique superdirectories in a set of Java File objects

Given an unordered set of Java File objects, I want to eliminate all those that are subdirectories (or files in subdirectories) of other Files in the set. For instance, given:
File("/john/paul/george/ringo")
File("/foo/bar/baz")
File("/foo/bar/elvis")
File("/john/paul")
File("/john/jacob")
File("/foo/bar/baz/qux/quux")
File("/john/")
File("/foo/bar/")
the set should reduce to:
File("/foo/bar/")
File("/john/")
I can imagine cobbling something together based on converting to Strings with File.getAbsolutePath() and sorting (possibly by length first, then lexicographically), but surely this is a solved problem, or at least somebody must already have written utility methods for things like determining whether one File is an ancestor of another.
I'm not the best of programmers, but here's my shot at it. There's quite a bit of recursion involved.
class UniqueDirectories {
private final Map<String, UniqueDirectories> directories = new HashMap<String, UniqueDirectories>();
private boolean locked = false;
public UniqueDirectories() {}
private UniqueDirectories(boolean locked) {
this.locked = locked;
}
public boolean add(String path) {
if (path == null)
return false;
if (path.isEmpty())
return false;
if (locked)
return false;
String[] tokens = path.split("(?<!^)[/\\\\]", 2);
UniqueDirectories existingDirectory = directories.get(tokens[0]);
if (existingDirectory == null) {
if (tokens.length < 2 || tokens[1].isEmpty()) {
directories.put(tokens[0], new UniqueDirectories(true));
return true;
} else {
UniqueDirectories newDirectory = new UniqueDirectories(false);
directories.put(tokens[0], newDirectory);
return newDirectory.add(tokens[1]);
}
} else if (tokens.length >= 2 && !tokens[1].isEmpty()) {
return existingDirectory.add(tokens[1]);
} else {
directories.put(tokens[0], new UniqueDirectories(true));
return true;
}
}
public List<String> toList(char delimiter) {
List<String> list = new ArrayList<String>();
for (Map.Entry<String, UniqueDirectories> entry : directories.entrySet()) {
if (entry.getValue().directories.size() == 0) {
list.add(entry.getKey());
} else {
for (String subdirectory : entry.getValue().toList(delimiter)) {
list.add(entry.getKey() + delimiter + subdirectory);
}
}
}
return list;
}
public static void main(String[] args) {
String[] testPaths = {
"/john/paul/george/ringo",
"/foo/bar/baz",
"/foo/bar/elvis",
"/john/paul",
"/john/jacob",
"/foo/bar/baz/qux/quux",
"/john/",
"/foo/bar/"
};
UniqueDirectories directories = new UniqueDirectories();
for (String path : testPaths) {
directories.add(path);
}
System.out.println(directories.toList('/'));
}
}
Sorry about the lack of comments. Too lazy to go back and do it, but at least the code's relatively short. I haven't put it through rigorous testing either (just used the ones you provided), so you may want to use some more test cases.
The biggest thing to be careful with is consistency. If you start a path with a delimiter, all paths should start with one. Conversely, if one path does not start with a delimiter, the rest shouldn't either. Otherwise, they will be treated as different paths. You could easily fix this by removing the lookbehind in the regex though; I just wasn't sure how you wanted it to behave.

simple conditional in java (unexpected issue)

I have an unexpected issue when using a conditional operator in java.
The code is supposed to check if the ArrayList contains a specific string, then it returns true or false. It is not the first time I do this, but for some reason there's something wrong.
This is my code so far:
public boolean isDone() {
ArrayList<String> al = new ArrayList<String>(); //Defining ArrayList
al.add(d1.getText()); // Adding the text from JLabels.
al.add(d2.getText());
al.add(d3.getText());
al.add(d4.getText());
al.add(d5.getText());
if(al.contains(".")) {
return false;
} else {
return true;
}
The issue is that when running the debugger, it should return falseand instead of that, it returnstrue. For some reason the conditional is not "reading" the content of the ArrayList, or stuff like that.
As you see, the ArrayList contains the . that needs the conditional to return false, but instead of that, it returns true. What is wrong in my code?
Try this:
public boolean isDone() {
ArrayList<String> al = new ArrayList<String>();
al.add(d1.getText());
al.add(d2.getText());
al.add(d3.getText());
al.add(d4.getText());
al.add(d5.getText());
for (String str : al)
if (str != null && str.contains("."))
return false;
return true;
}
You have to check each string individually, the contains() method in ArrayList will return true only if the exact string "." is present in the list, not if one of the strings in the list contains a dot.
When you use a1.contains(...), you are checking if any sting in array is ".". This is different from your intention to check if any string in array "a1" contains '.' char as I understand.
If you need to check if any string in array contains "." text it can be like this:
for(String text : a1) {
if(text != null && text.indexOf(".") >= 0) {
return false;
}
}
return true;
Your List<String> does not contain the String that equals ".". You have a String that contains a . but that is not the same thing. You can do that with String.contains(CharSequence),
public boolean isDone() {
List<String> al = new ArrayList<String>(); // <-- I would use the Interface type
al.add(d1.getText());
al.add(d2.getText());
al.add(d3.getText());
al.add(d4.getText());
al.add(d5.getText());
// If any String in al contains a '.' return false, else true.
for (String str : al) {
if (str.contains(".")) {
return false;
}
}
return true;
}

Categories