How to get non-inclusive index of substring? - java

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

Related

JAVA return longest value if a string contains any of the items from a List

I have the following array of code types:
["sample_code","code","formal_code"]
and the following ids:
String id="123456789_sample_code_xyz";
String id2="91343486_code_zxy";
I want to extract the code type from the ids
this is my code snippet:
String codeTypes[] = {"sample_code","code","formal_code"};
String id= "123456789_sample_code_xyz";
String codeType = Arrays.stream(codeTypes).parallel().filter(id::contains).findAny().get();
System.out.println(codeType);
it doesnt work with the 1st id, because it returns "code" instead of "sample_code", I want to get the longest code type.
for the 1st id the code type should be "sample_code"
for the 2nd id the code type should be "code"
Check for the longest code types first. This means the following changes to your code:
Sort the code types by length descending.
Don’t use a parallel stream. A parallel stream hasn’t got an order. A sequential stream makes sure the code types are checked in order.
Use findFirst(), not findAny() to make sure you get the first match.
So it becomes:
String codeTypes[] = { "sample_code", "code", "formal_code" };
Arrays.sort(codeTypes, Comparator.comparing(String::length).reversed());
String id = "123456789_sample_code_xyz";
Optional<String> codeType = Arrays.stream(codeTypes).filter(id::contains).findFirst();
codeType.ifPresent(System.out::println);
Now output is:
sample_code
You can do it as follows:
public class Main {
public static void main(String[] args) {
String[] ids = { "123456789_sample_code_xyz", "91343486_code_zxy" };
String[] codeTypes = { "sample_code", "code", "formal_code" };
String max;
for (String id : ids) {
max = "";
for (String codeType : codeTypes) {
if (id.contains(codeType)) {
if (max.length() < codeType.length()) {
max = codeType;
}
}
}
System.out.println(id + " : " + max);
}
}
}
Output:
123456789_sample_code_xyz : sample_code
91343486_code_zxy : code
Since you run the strem in parallel, you cannot predict which of the streams finds first a matching pattern. I your case (also in mine when I tried your code snippet) the second stream which looked for "code" was faster, and the whole stream terminates because you just want "findAny()".
Remove the "parallel" and your code works as you expect.
Well, stream API is not suitable for every problem. I think you can use a non-stream version to solve your problem.
I just looped over codeTypes array and for every codeType, have replaced idx with empty string then calculate its length and find min length between idX string and replace.
now if minSize length with replace string length is the same, then it is the candidate for the final result. minSize != id.length() is for when the time that there is not any codeType.
private static String findCodeType(String id, String[] codeTypes) {
int minSize = id.length();
String codeType = "NotFound";
for (String code : codeTypes) {
String replace = id.replaceAll(code, "");
minSize = Integer.min(minSize, replace.length());
if (minSize == replace.length() && minSize != id.length())
codeType = code;
}
return codeType;
}

Comparing Two strings with different order

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;
}

Retrieve strings prefixed by a string in an array

Write a Java code of the method that takes an array of strings and a String (S(. The method should return an integer that is the number of strings that starts with S.
For example if:
array_words = { "All", "Arab", "size", "Almond", "Allowed", "here"} and S= "All", then the method should return 2
what is the idea of searching here ?
The best, fastest and cheapest solution, for a larger input though, is to store all words of the array into a DWAG.
That would bring the memory requirements to almost optimal for storing all words and would give a search time complexity of O(m) (m being the size of S).
A slightly less memory optimal structure would be a trie.
Some people ask homework questions sometimes on SOF, and sometimes they get answers a little out of scope.
Loop through the array and use the startsWith method.
I know you can take it up from here.
Iterate over the array and check if each element in the array starts with string S. If it does, increment the count variable.
Return the count variable after iterating over the array.
public class stack {
public static void main(String[] args) {
String[] arr = { "All", "Arab", "size", "Almond", "Allowed", "here"};
String S = "All";
System.out.println(numberOfOccurrences(S, arr));
}
public static int numberOfOccurrences(String S, String[] array_words) {
int count = 0;
for (String stringElement : array_words) {
if (stringElement.startsWith(S)) {
count++;
}
}
return count;
}
}

Recursive method works in java with console, but not with android

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.

implement binary search with string prefix?

How can I implement binary search to find a string with a particular prefix in generic array (which in this case will be a string[]). I tried compareTo but that wouldn't help because i have to use a string prefix. eg String prefix "Bi" bill, bilards ...etc..
Implement the following method to return all strings in an alphabetically sorted array that start with a given prefix. For instance, given a prefix “bi”, the returned strings are ”Bill Clinton”, ”Bill Gates”, and ”Bill Joy”. Note that all string comparisons should be case INSENSITIVE. The strings in the returned list must be in the order in which they appear in the array. Your implementation must be based on binary search, and must run in worst case O(log n+k) time, where n is the length of the array, and k is the number of matching strings. Assume that the array has no duplicate entries. If there are no matches, you may either return null, or an empty array list.
You may use the following String methods (in addition to any others you may recall):
boolean startsWith(String s)
int compareTo(String s)
int compareToIgnoreCase(String s)
String toLowerCase(String s)
String toUpperCase(String s)
(As for ArrayList, you only need to use the add method to add an item to the end of the array list.)
You may write helper methods (with full implementation) as necessary. You may not call any method that you have not implemented yourself
public static <T extends Comparable<T>> ArrayList prefixMatch(T[] list, String prefix) {
ArrayList<T> result = new ArrayList<T>();
int lo = 0;
int hi = list.length - 1;
while(lo <= hi) {
int mid = (hi + lo) / 2;
list[mid].startsWith(prefix) ? 0 : list[mid].compareTo((T) prefix));
}
return null;
}
You can use default binary search with custom comparator as your base, and then work our range by your self. I think the right algorithm would be:
Perform binary search on given array. Use comparator which checks only for prefix.
As result you'll get index of string which starts with your prefix
Walk to the left to find first string which matches prefix, remember position.
Walk to the right to find first string which matches prefix, remember position.
Copy elements from range start to range end from original array. That will be your desired array of all elements with prefix match condition.
Below is implementation in java. It works in happy case scenario but will crash if(I left those checks out to make code look simple):
No strings with given prefix exist in original array
There are string with length less then prefix length
Also if you need binary search implementation you could check source of Arrays.binarySearch
public class PrefixMatch {
public static void main(String[] args) {
final String[] prefixMathces = prefixMatch(new String[] { "Abc", "Abcd", "Qwerty", "Pre1", "Pre2", "Pre3", "Xyz", "Zzz" }, "pre");
for (int i = 0; i < prefixMathces.length; i++)
System.out.println(prefixMathces[i]);
}
public static String[] prefixMatch(final String[] array, final String prefix) {
final Comparator<String> PREFIX_COMPARATOR = new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o1.substring(0, prefix.length()).compareToIgnoreCase(o2);
}
};
final int randomIndex = Arrays.binarySearch(array, prefix, PREFIX_COMPARATOR);
int rangeStarts = randomIndex, rangeEnds = randomIndex;
while (rangeStarts > -1 && array[rangeStarts].toLowerCase().startsWith(prefix.toLowerCase()))
rangeStarts--;
while (rangeEnds < array.length && array[rangeEnds].toLowerCase().startsWith(prefix.toLowerCase()))
rangeEnds++;
return Arrays.copyOfRange(array, rangeStarts + 1, rangeEnds);
}
}
I assume that you currently have something like this? :
arrayElement.compareTo(prefix)
If so, you can change it to look like this:
arrayElement.startsWith(prefix) ? 0 : arrayElement.compareTo(prefix)
I suggest looking into the API code for this. There is an Arrays class that you can check out in the java.lang package and learn from there.
Working on a similar problem right now. I believe pseudo code will go something like yours. I created a pojo class Song. A song is made up up three strings artist,title, and lyrics.
When you create a song object you get :
// Artist Title Lyrics..
Song a = ["Farmer Brown", "Oh' Mcdonalad", "Oh'mcdonal had a farm eh i oh i oh"]
public class Song implements Comparable<Song> {
private String _artist;
private String _lyrics;
private String _title;
// constructor
public Song(String artist, String title, String lyrics) {
this._artist = artist;
this._title = title;
this._lyrics = lyrics;
}
public String getArtist() {
return _artist;
}
public String getLyrics() {
return _lyrics;
}
public String getTitle() {
return _title;
}
public String toString() {
String s = _artist + ", \"" + _title + "\"";
return s;
}
//This compare two song objects
public int compareTo(Song song) {
String currentSong = song.toString();
int x = currentSong.compareToIgnoreCase(this.toString());
return x;
}
This is your method here that will take in the array of songs and your prefix and use the compare method to see if they match. If they match the compareTo method returns a 0. If you get a 0 then you know you have found your song so return the arrayOfSongs[index where song is found].
I have not coded up my search yet but I modified yours to match my code. I have not tested it yet. I don't think you even need a compareTo method but you can use it. Also for scaling the binary search should return a list of songs that might match as you might have multiple songs that start with "xyz" . Kind of when you start searching on google with prefix "do" you get a drop down of "dog, donut,double" which gives the user something to choose like a search engine.
public static ArrayList<Song> search (String[] arrayOfSongs , String enteredPrefix) {
ArrayList<Song> listOfMatches = new ArrayList<Song>;
int mid;
int lo = 0;
int hi = arrayOfSongs.length - 1;
while(lo <= hi)
{
mid = (hi + lo) / 2;
if(arrayOfSongs[mid].startsWith(enteredPrefix))
{
System.out.println("Found a match, adding to list");
listOfMatches.add(arrayOfSongs[mid]);
}
}
return listOfMatches;
}
Once you have a listOfMatches of possible suspects of the song you want you can use the compareTo method in some way.

Categories