I facing some issue with write logic for below problem.
I have two ArrayLists of strings:
List1: contains 5 million strings
List2: will create on users input and contains some strings/characters(Ex. a,b,c,g,l,pd,sp,mta)
Now I have to split list1 into multiple Lists according to startsWith strings in list2 like in above case. I need to create 8 lists as starts with 'a', 'b','c', 'g', 'l','pd', 'sp' and 'mta'
But the condition for above is I have to iterate List1 or List2 only once. i.e. worst complexity for algorithm should be size of List1 (5 million).
It is allowed to use collections.sort() method
Code I have tried
// Create List for search strings.
List<String> CharList = new ArrayList<String>();
CharList.add("a");
CharList.add("b");
CharList.add("e");
CharList.add("z");
CharList.add("4");
CharList.add("1");
CharList.add("zi");
List<String> recordList = new ArrayList<String>();
// Creating dummy data with 100 character in live environment it can be
// around 50 lakhs strings
for (int i = 0; i < 100; i++) {
char[] chars = "abcdefghijklmnopqrstuvwxyzABCGDKL0123456789".toCharArray();
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i1 = 0; i1 < 6; i1++) {
char c = chars[random.nextInt(chars.length)];
sb.append(c);
}
String output = sb.toString();
recordList.add(output);
}
// Adding some data mannually
recordList.add("zink");
recordList.add("zebra");
recordList.add("zzzzzz");
Collections.sort(CharList, String.CASE_INSENSITIVE_ORDER);
Collections.sort(recordList, String.CASE_INSENSITIVE_ORDER);
System.out.println("RECORDLIST ===>" + recordList);
System.out.println("***************************************************");
System.out.println("Charlist ===>" + CharList);
System.out.println("***************************************************");
List<List> lists = new ArrayList<List>();
int startIndex = 0, charPointer = 0;
while (startIndex < recordList.size() && charPointer < CharList.size()) {
List<String> temp = new ArrayList<String>();
boolean isHit = false;
String currentRecord = recordList.get(startIndex);
String partitionSattement = CharList.get(charPointer);
while (currentRecord.startsWith(partitionSattement.toUpperCase())
|| currentRecord.startsWith(partitionSattement.toLowerCase())) {
temp.add(recordList.get(startIndex));
isHit = true;
startIndex++;
}
if (!isHit) {
startIndex++;
}
if (!temp.isEmpty()) {
lists.add(temp);
System.out.println(CharList.get(charPointer) + "====>" + temp);
}
charPointer++;
}
Just using the String startsWith method won't work in this case. Consider what happens if the first pattern does not match any input - you'll loop through all strings in the input list without finding a match, even though subsequent pattern matches do exist.
What we need to do instead is compare each pattern against the initial characters of each input string and process accordingly. Let's say we have an input string str and a pattern pat. Let subStr be the first pat.length() characters of str. Now we can compare subStr and pat using the String compareToIgnoreCase method. There are three cases to consider:
subStr < pat Move to the next input string.
subStr == pat Add str to output for pat and move to the next input string.
subStr > pat Move to the next pattern.
Here's some code to illustrate (I've kept your variable names where possible).
List<List<String>> output = new ArrayList<>();
for(int i=0; i<CharList.size(); i++) output.add(new ArrayList<String>());
int startIndex=0;
int charPointer=0;
while(startIndex < recordList.size() && charPointer < CharList.size())
{
String charStr = CharList.get(charPointer);
String recStr = recordList.get(startIndex);
int cmp;
if(recStr.length() < charStr.length())
{
cmp = -1;
}
else
{
String recSubStr = recStr.substring(0, charStr.length());
cmp = recSubStr.compareToIgnoreCase(charStr);
}
if(cmp <= 0)
{
if(cmp == 0) output.get(charPointer).add(recStr);
startIndex++;
}
else
{
charPointer++;
}
}
for(int i=0; i<CharList.size(); i++)
{
System.out.println(CharList.get(i) + " : " + output.get(i));
}
Also, you should note that when you include a pattern that itself starts with another pattern (e.g. "zi" and "z") the longer pattern will never be matched, since the shorter one will capture all inputs.
I can see two problems in your code:
You should remove the following segment:
if (!isHit) {
startIndex++;
}
Actually you don't need that isHit variable at all. If a string doesn't match with a pattern then you still have to compare it with the next pattern.
You should sort the arrays in descending order. As SirRaffleBuffle noted in the other answer you should compare the strings with the longer pattern first. Sorting the strings and patterns in descending order will automatically solve this problem.
Related
I've been trying to get each character from every String by column but I only got the first characters of every string, I want to get every character by column from every string.
For example:
I have three strings from ArrayList of Strings:
chi
llo
ut
What I want to happen must be like this, after getting each character by column from strings:
clu
hlt
io
So long, my current source code only gets the first characters of first two string which is 'cl', Here's my current source code:
List<String> New_Strings = new ArrayList<String>();
int Column_Place = 0;
for (String temp_str : Strings) {
try{ //For StringIndexOutOfBoundsException (handle last String)
if(Column_Place >= temp_str.length()){
Current_Character = temp_str.charAt(Column_Place);
New_Strings.add(Character.toString(Current_Character));
break;
}else if (Column_Place < temp_str.length()){
Current_Character = temp_str.charAt(Column_Place);
New_Strings.add(Character.toString(Current_Character));
}
}catch(Exception e){
continue;
}
Column_Place++;
}
You're adding string representations of the individual characters to the result string. Instead, you should accumulate these characters in to a result string. E.g.:
int numStrings = strings.size();
List<String> result = new ArrayList<>(numStrings);
for (int i = 0; i < numStrings; ++i) {
StringBuilder sb = new StringBuilder();
for (String s : strings) {
if (i < s.length) {
sb.append(s.charAt(i));
}
}
result.add(sb.toString());
}
Just call groupByColumn(Arrays.asList("chi", "llo", "ut"):
public static List<String> groupByColumn(List<String> words) {
if (words == null || words.isEmpty()) {
return Collections.emptyList();
}
return IntStream.range(0, longestWordLength(words))
.mapToObj(ind -> extractColumn(words, ind))
.collect(toList());
}
public static String extractColumn(List<String> words, int columnInd) {
return words.stream()
.filter(word -> word.length() > columnInd)
.map(word -> String.valueOf(word.charAt(columnInd)))
.collect(Collectors.joining(""));
}
public static int longestWordLength(List<String> words) {
String longestWord = Collections.max(words, Comparator.comparing(String::length));
return longestWord.length();
}
You iterate on the List with a enhanced/foreach loop.
So you will iterate a single time on each
String. Whereas your result : only the first letters are hanlded.
You should use a while loop with as while condition while(Column_Place < Strings.size()) with such an approach.
Or as alternative you could do things in two distinct steps and use Java 8 features.
Note that in Java, variables starts with lowercase. Please follow the conventions to make your code more readable/understandable here and there.
In Java 8 you could do :
List<String> strings = new ArrayList<>(Arrays.asList("chi", "llo", "ut"));
int maxColumn = strings.stream()
.mapToInt(String::length)
.max()
.getAsInt(); // suppose that you have at least one element in the List
List<String> values =
// stream from 0 the max number of column
IntStream.range(0, maxColumn)
// for each column index : create the string by joining their
// String value or "" if index out of bound
.mapToObj(i -> strings.stream()
.map(s -> i < s.length() ? String.valueOf(
s.charAt(i)) : "")
.collect(Collectors.joining()))
.collect(Collectors.toList());
just think the list as two dimensional array. split each item from the list, get the j-th character from each item, if and only if the item's length is greater than the index j.
ArrayList<String> list = new ArrayList<String>();
list.add("chi");
list.add("llo");
list.add("ut");
int size = list.size();
int i=0, j=0,k=0;
while(size-- > 0){
for(i=0; i<list.size(); i++){
String temp = list.get(i);
if(j < temp.length()){
System.out.print(temp.charAt(j));
}
}
j++;
System.out.println();
}
Trying to search for patterns of letters in a file, the pattern is entered by a user and comes out as a String, so far I've got it to find the first letter by unsure how to make it test to see if the next letter also matches the pattern.
This is the loop I currently have. any help would be appreciated
public void exactSearch(){
if (pattern==null){UI.println("No pattern");return;}
UI.println("===================\nExact searching for "+patternString);
int j = 0 ;
for(int i=0; i<data.size(); i++){
if(patternString.charAt(i) == data.get(i) )
j++;
UI.println( "found at " + j) ;
}
}
You need to iterate over the first string until you find the first character of the other string. From there, you can create an inner loop and iterate on both simultaneously, like you did.
Hint: be sure to look watch for boundaries as the strings might not be of the same size.
You can try this :-
String a1 = "foo-bar-baz-bar-";
String pattern = "bar";
int foundIndex = 0;
while(foundIndex != -1) {
foundIndex = a1.indexOf(pattern,foundIndex);
if(foundIndex != -1)
{
System.out.println(foundIndex);
foundIndex += 1;
}
}
indexOf - first parameter is the pattern string,
second parameter is starting index from where we have to search.
If pattern is found, it will return the starting index from where the pattern matched.
If pattern is not found, indexOf will return -1.
String data = "foo-bar-baz-bar-";
String pattern = "bar";
int foundIndex = data.indexOf(pattern);
while (foundIndex > -1) {
System.out.println("Match found at: " + foundIndex);
foundIndex = data.indexOf(pattern, foundIndex + pattern.length());
}
Based on your request, you can use this algorithm to search for your positions:
1) We check if we reach at the end of the string, to avoid the invalidIndex error, we verify if the remaining substring's size is smaller than the pattern's length.
2) We calculate the substring at each iteration and we verify the string with the pattern.
List<Integer> positionList = new LinkedList<>();
String inputString = "AAACABCCCABC";
String pattern = "ABC";
for (int i = 0 ; i < inputString.length(); i++) {
if (inputString.length() - i < pattern.length()){
break;
}
String currentSubString = inputString.substring(i, i + pattern.length());
if (currentSubString.equals(pattern)){
positionList.add(i);
}
}
for (Integer pos : positionList) {
System.out.println(pos); // Positions : 4 and 9
}
EDIT :
Maybe it can be optimized, not to use a Collection for this simple task, but I used a LinkedList to write a quicker approach.
Hi biologist here with a little bit of coding background. my goal is to be able to input a string of characters and the code to be able to tell me how many times they occur and at what location in the string.
so ill be entering a string and i want the location and abundance of sq and tq within the string. with the location being the first character e.g njnsqjjfl sq would be located at postition 4.
This is what ive come up with so far (probably very wrong)
string S = "...";
int counter =0;
for(int i=0; i<s.length; i++){
if(s.charAt (i) == 'sq')}
counter++;})
string S = "...";
int counter =0;
for(int i=0; i<s.length; i++){
if(s.charAt (i) == 'tq')}
counter++;})
any input will help, thankyou
So , you can have multiple occurrences of "sq" and "tq" in your code, so you can have 2 arraylists to save these two separately(or one to save them together).
ArrayList<Integer>sqLocation = new ArrayList<>();
ArrayList<Integer>tqLocation = new ArrayList<>();
for(int i =0;i<s.length()-1;i++){
if(s.charAt(i)=='s' && s.charAt(i+1)=='q'){
sqLocation.add(i);
}
else if(s.charAt(i)=='t' && s.charAt(i+1)=='q'){
tqLocation.add(i);
}
}
System.out.println("No. of times sq occurs = "+sqLocation.size());
System.out.println("Locations ="+sqLocation);
System.out.println("No. of times tq occurs = "+tqLocation.size());
System.out.println("Locations ="+tqLocation);
This can be achieved using regex. Your use case is to count occurrences and position of those occurrences. The method match returns an integer list which is position and count is size of list
Exmaple code
public class RegexTest {
public static List<Integer> match(String text, String regex) {
List<Integer> matchedPos = new ArrayList<>();
Matcher m = Pattern.compile("(?=(" + regex + "))").matcher(text);
while(m.find()) {
matchedPos.add(m.start());
}
return matchedPos;
}
public static void main(String[] args) {
System.out.println(match("sadfsagsqltrtwrttqsqsqsqsqsqs", "sq"));
System.out.println(match("sadfsagsqltrtwrttqksdfngjfngjntqtqtqtqtqtq", "tq"));
}
}
what you want is a HashMap <String, List <Integer>>
this will hold, the String that you are looking for e.g. sq or tq, and a List of the positions that they are at.
You want to loop around using String.indexOf see https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#indexOf(java.lang.String,%20int)
psuedocode being
String contents = "sadfsagsqltrtwrttqksdfngjfngjntqtqtqtqtqtq";
map.add (lookFor, new ArrayList ());
int index = 0;
while ((index = contents.indexOf (lookFor, index)) != -1) {
list = map.get (lookFor);
list.add (index);
}
You should use not charAt but substring to get a part of String.
int count(String s, String target) {
int counter = 0;
int tlen = target.length();
for (int i = tlen; i < s.length(); i++) {
if (s.substring(i - tlen, i).equals(target)) {
counter++;
}
}
return counter;
}
// in some method
count("...", "sq");
count("...", "tq");
I have been spending hours trying to work through the logic of finding a palindrome within this context. So we are given an arraylist of strings that are single words and we need to find the biggest palindromes from the list of words. As an example ["mr", "owl", "ate", "my", "metal", "worm", "racecar", "mad", "am"] would construct an araylist with the following result ["mrowlatemymetalworm", "racecar", "madam"]. So far I have been playing around with the iterations but can't seem to get the correct logic of how to iterate from both ends, especially when it comes to switching inner strings indexes from the other end... Here is what I have so far.
List<String> list = Arrays.asList("mr", "owl", "ate", "my", "metal", "worm", "racecar", "mad", "am");
List<String> palindromeList = new ArrayList<String>();
int i = 0;
int j = list.get(i).length();
int l = list.size()-1;
int s = list.get(l).length() -1;
while (i<j){
while (j<list.get(i).length()){
if (s == 0){
//need to reinitialize s for previous index of back end of list for possible palindrome
}
if (list.get(l).charAt(s) == list.get(i).charAt(j)){
l--;
}
else if (list.get(l).charAt(s) != list.get(i).charAt(j)){
j++;
s--;
}
}
}
//once outer loop breaks the result should be added to palindromeList
You can verify if string is a palindrome by comparaing if it's equal with itself reversed (that's exact definition):
public static boolean isPalindrome(String value) {
if (value == null || value.isEmpty())
return false;
return new StringBuilder(value).reverse().toString().equals(value);
}
I'm not sure if I understood the logic you want to apply, but based on the input and output you gave I came up with something like this:
List<String> list = Arrays.asList("mr", "owl", "ate", "my", "metal", "worm", "racecar", "mad", "am");
List<String> palindromeList = new ArrayList<String>();
for (int i = 0; i < list.size(); ++i) {
String longestPalindrome = null;
String candidate = "";
for (int j = i; j < list.size(); ++j) {
candidate += list.get(j);
if (isPalindrome(candidate))
longestPalindrome = candidate;
}
if (longestPalindrome != null)
palindromeList.add(longestPalindrome);
}
To detect if a string is a palindrome, I split the string in half, reverse the string and see if both sides equal each other.
There are 2 scenarios:
Word has even number of characters:
If the string is of odd length, we split the string into 2 substrings excluding the middle character: Ex: ABCBA would be broken into AB and BA. We then reverse the string and compare to see if they equal each other.
Word has odd number of characters:
If the string is of even length, we just split the string into 2 equal size substrings and reverse one of them then compare to see if they are the same string. Ex: Hannah would be Han and nah.
List<String> list = Arrays.asList("mr", "owl", "ate", "my", "metal", "worm", "racecar", "mad", "am");
List<String> palindromeList = new ArrayList<String>();
//Detects if a string is a palindrome.
for (int i = 0; i < list.size(); i ++) {List<String> palindromeList = new ArrayList<String>();
int wordLength = list.get(i);
String leftSide = "";
String rightSide ="";
if (wordLength%2 == 1) { //If word has odd number of characters.
leftSide = list.get(i).subString(0,wordLength/2);
rightSide = list.get(i).subString((wordLength/2) + 1, wordLength);
} else { //If word has even number of characters.
leftSide = list.get(i).subString(0,(wordLength/2));
rightSide = list.get(i).subString((wordLength/2), wordLength);
}
String reversedLeftSide = new StringBuilder(leftSide).reverse().toString();
if (reversedLeftSide.equals(rightSide)) {
palindromeList.add(list.get(i));
}
}
String longestPalindrome = "";
//Searches for longest palindrome in the list of palindromes.
for (int i = 0; i < palindromeList.size(); i++) {
if (palindromeList.get(i).length() > longestPalindrome.length()) {
longestPalindrome = palindromeList.get(i);
}
}
System.out.println(longestPalindrome); //This should give you longest palindrome.
Keep in mind there are probably a dozen ways to solve this problem and I've just proposed one solution. This code might also contain 1 or 2 minor bugs as it has not been tested.
It's important to know whether words can be repeated or not. If they can, then you could have "racecarracecar", "racecarracecarracecar", etc., so I assume they can't. In that case we can proceed as follows. Walk through the list of words, starting with "mr". If the palindrome begins with "mr" it must end with "m". Does "am" work? No. Try other possibilities; "worm" works. Then an "o" must follow "mr". The next word at the beginning must be "owl". That means the next word at the end must end with "l" so must be "metal".
Etc., until you 1) run out of words, 2) have a palindrome, or 3) have a palindrome like "doggod" where word boundaries are exactly in the middle, in which case you can (recursively) search for more palindromes with the remaining words and put anything you get in the middle, like "dogracecargod" or "dogmadamgod" or "dogmrowlatemymetalwormgod".
I have a String ArrayList consisting alphabets followed by a digit as a suffix to each of the alphabet.
ArrayList <String> baseOctave = new ArrayList();
baseOctave.add("S1");
baseOctave.add("R2");
baseOctave.add("G4");
baseOctave.add("M2");
baseOctave.add("P3");
baseOctave.add("D1");
baseOctave.add("N1");
I pass the strings from this baseOctave and few other characters as input pattern for creating an object.
MyClass obj1 = new MyClass ("S1,,R2.,M2''-");
Since I frequently make use of these kind of input patterns during object instantiation, I would like to use simple characters S, R, G, M etc.
Ex:
MyClass obj1 = new MyClass ("S,,R.,M''-");
MyClass obj2 = new MyClass ("S1,G.,M,D1");
So the alphabets used during object creation may contain digits as suffix or it may not have digit as suffix.
But inside the constructor (or in separate method), I would like to replace these simple alphabets with alphabets having suffix. The suffix is taken from the baseOctave.
Ex: above two strings in obj1 and obj2 should be "S1,,R2.,M2''-" and "S1,G4.,M2,D1"
I tied to do this, but could not continue the code below. Need some help for replacing please..
static void addSwaraSuffix(ArrayList<String> pattern) {
for (int index = 0; index < pattern.size(); index++) {
// Get the patterns one by one from the arrayList and verify and manipulate if necessary.
String str = pattern.get(index);
// First see if the second character in Array List element is digit or not.
// If digit, nothing should be done.
//If not, replace/insert the corresponding index from master list
if (Character.isDigit(str.charAt(1)) != true) {
// Replace from baseOctave.
str = str.replace(str.charAt(0), ?); // replace with appropriate alphabet having suffix from baseOctave.
// Finally put the str back to arrayList.
pattern.set(index, str);
}
}
}
Edited information is below:
Thanks for the answer. I found another solution and works fine. below is the complete code that I found working. Let me know if there is any issue.
static void addSwaraSuffix(ArrayList<String> inputPattern, ArrayList<String> baseOctave) {
String temp = "";
String str;
for (int index = 0; index < inputPattern.size(); index++) {
str = inputPattern.get(index);
// First see if the second character in Array List is digit or not.
// If digit, nothing should be done. If not, replace/insert the corresponding index from master list
// Sometimes only one swara might be there. Ex: S,R,G,M,P,D,N
if (((str.length() == 1)) || (Character.isDigit(str.charAt(1)) != true)) {
// Append with index.
// first find the corresponsing element to be replaced from baseOctave.
for (int index2 = 0; index2 < baseOctave.size(); index2++) {
if (baseOctave.get(index2).startsWith(Character.toString(str.charAt(0)))) {
temp = baseOctave.get(index2);
break;
}
}
str = str.replace(Character.toString(str.charAt(0)), temp);
}
inputPattern.set(index, str);
}
}
I assume that abbreviation is only one character and that in full pattern second character is always digit. Code below relies on this assumptions, so please inform me if they are wrong.
static String replace(String string, Collection<String> patterns) {
Map<Character, String> replacements = new HashMap<Character, String>(patterns.size());
for (String pattern : patterns) {
replacements.put(pattern.charAt(0), pattern);
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < string.length(); i++) {
Character c = string.charAt(i);
char next = i < string.length() - 1 ? string.charAt(i + 1) : ' ';
String replacement = replacements.get(c);
if (replacement != null && (next <= '0' || next >= '9')) {
result.append(replacement);
} else {
result.append(c);
}
}
return result.toString();
}
public static void main(String[] args) {
ArrayList<String> baseOctave = new ArrayList<String>();
baseOctave.add("S1");
baseOctave.add("R2");
baseOctave.add("G4");
baseOctave.add("M2");
baseOctave.add("P3");
baseOctave.add("D1");
baseOctave.add("N1");
System.out.println(replace("S,,R.,M''-", baseOctave));
System.out.println(replace("S1,G.,M,D1", baseOctave));
System.out.println(replace("", baseOctave));
System.out.println(replace("S", baseOctave));
}
Results:
S1,,R2.,M2''-
S1,G4.,M2,D1
S1