getting the words before a specific String value - java

I asked a question about the following method a while ago and came up with quite different question. Suppose I have String A B -> C or A B -> carry sum or X Y Cin -> Cout Sum. How can I extract the words before -> without including ->? And then extracting the words after ->?
public void parseContactsLine(String line)
{
String[] words = line.split("->");
for(int i = 0; i < words.length; i++)
{
}
}

Your first split for "->" will separate into two strings the list of words of each side.
Then you can re-split by spaces using .split("\\s"); to get a list of each words.
You would end up with
String[] wordsAfterLambda = line.split("->")[1].split("\\s");
for(String s : wordsAfterLambda)
System.out.println(s);
Notice that I used a for-each instead of for which I tend to prefer when there is no need to keep the index.
Edit
As per your comment, the [1] is to access the array value and not linked to the split itself, it is the same as doing
String[] words = line.split("->");
String[] wordsAfterLambda = words[1].split("\\s");

Related

Comparing two Strings if word spacing and capitalization do not matter-Java

What I want to do is create a method that takes two objects as input
of type String. The method will return logical truth if both strings are the same (word spacing and capitalization do not matter). I thought to split String, make an Array of elements, add each element to List and then compare each element to space and remove it from List. At the end use a compareToIgnoreCase() method. I stopped on removing space from List for string2. It works to string1List and doesn't work to string2List, I'm wondering why?? :(
I will be grateful for help, I spend a lot of time on it and I'm stuck. Maybe someone know a better solution.
import java.util.ArrayList;
import java.util.List;
public class Strings {
public static void main(String[] args) {
String string1 = "This is a first string";
String string2 = "this is a first string";
String[] arrayOfString1 = string1.split("");
List<String> string1List = new ArrayList<>();
for (int i = 0; i < arrayOfString1.length; ++i) {
string1List.add(arrayOfString1[0 + i]);
}
String[] arrayOfString2 = string2.split("");
List<String> string2List = new ArrayList<>();
for (int i = 0; i < arrayOfString2.length; ++i) {
string2List.add(arrayOfString2[0 + i]);
}
for (int i = 0; i < string1List.size(); ++i) {
String character = string1List.get(0 + i);
if (character.equals(" ")) {
string1List.remove(character);
}
}
for (int i = 0; i < string2List.size(); ++i) {
String character = string2List.get(0 + i);
if (character.equals(" ")) {
string2List.remove(character);
}
}
System.out.println(string2List.size());
}
}
You can try below solution. As you mentioned word spacing and capitalization do not matter
1.remove capitalization - using toLowercase()
2.for word spacing - remove all word spacing using removeAll() with regex pattern "\\s+" so it removes all spaces.
3. check both strings now.
public class StringChecker {
public static void main(String[] args) {
System.out.println(checkString("This is a first string", "this is a first string"));
}
public static boolean checkString(String string1, String string2){
String processedStr1 = string1.toLowerCase().replaceAll("\\s+", "");
String processedStr2 = string2.toLowerCase().replaceAll("\\s+", "");
System.out.println(" s1 : " + processedStr1);
System.out.println(" s2 : " + processedStr2);
return processedStr1.equals(processedStr2);
}
}
Your problem has nothing to do with spaces. You can replace them with any other character (for example "a") to test this. Therefore, removing spaces in any of the methods given above will not improve your code.
The source of the problem is iterating the list with the for command. When you remove an item from a list inside the for loop, after removing the i-th element, the next element in the list becomes the i-th current element.
On the next repetition of the loop - when i is incremented by one - the current i + 1 item becomes the next item in the list, and thus you "lose" (at least) one item. Therefore, it is a bad idea to iterate through the list with the for command.
However you may use many other methods available for collections - for instance Iterators - and your program will work fine.
Iterator <String> it = string1List.iterator();
while(it.hasNext())
{
if(it.next().equals("a")) it.remove();
}
Of course there is no need at all to use Lists to compare these two strings.

Count occurrences in 2D Array

I'm trying to count the occurrences per line from a text file containing a large amount of codes (numbers).
Example of text file content:
9045,9107,2376,9017
2387,4405,4499,7120
9107,2376,3559,3488
9045,4405,3559,4499
I want to compare a similar set of numbers that I get from a text field, for example:
9107,4405,2387,4499
The only result I'm looking for, is if it contains more than 2 numbers (per line) from the text file. So in this case it will be true, because:
9045,9107,2376,9017 - false (1)
2387,4405,4499,7120 - true (3)
9107,2387,3559,3488 - false (2)
9045,4425,3559,4490 - false (0)
From what I understand, the best way to do this, is by using a 2d-array, and I've managed to get the file imported successfully:
Scanner in = null;
try {
in = new Scanner(new File("areas.txt"));
} catch (FileNotFoundException ex) {
Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
List < String[] > lines = new ArrayList < > ();
while ( in .hasNextLine()) {
String line = in .nextLine().trim();
String[] splitted = line.split(", ");
lines.add(splitted);
}
String[][] result = new String[lines.size()][];
for (int i = 0; i < result.length; i++) {
result[i] = lines.get(i);
}
System.out.println(Arrays.deepToString(result));
The result I get:
[[9045,9107,2376,9017], [2387,4405,4499,7120], [9107,2376,3559,3488], [9045,4405,3559,4499], [], []]
From here I'm a bit stuck on checking the codes individually per line. Any suggestions or advice? Is the 2d-array the best way of doing this, or is there maybe an easier or better way of doing it?
The expected number of inputs defines the type of searching algorithm you should use.
If you aren't searching through thousands of lines then a simple algorithm will do just fine. When in doubt favour simplicity over complex and hard to understand algorithms.
While it is not an efficient algorithm, in most cases a simple nested for-loop will do the trick.
A simple implementation would look like this:
final int FOUND_THRESHOLD = 2;
String[] comparedCodes = {"9107", "4405", "2387", "4499"};
String[][] allInputs = {
{"9045", "9107", "2376", "9017"}, // This should not match
{"2387", "4405", "4499", "7120"}, // This should match
{"9107", "2376", "3559", "3488"}, // This should not match
{"9045", "4405", "3559", "4499"}, // This should match
};
List<String[] > results = new ArrayList<>();
for (String[] input: allInputs) {
int numFound = 0;
// Compare the codes
for (String code: input) {
for (String c: comparedCodes) {
if (code.equals(c)) {
numFound++;
break; // Breaking out here prevents unnecessary work
}
}
if (numFound >= FOUND_THRESHOLD) {
results.add(input);
break; // Breaking out here prevents unnecessary work
}
}
}
for (String[] result: results) {
System.out.println(Arrays.toString(result));
}
which provides us with the output:
[2387, 4405, 4499, 7120]
[9045, 4405, 3559, 4499]
To expand on my comment, here's a rough outline of what you could do:
String textFieldContents = ... //get it
//build a set of the user input by splitting at commas
//a stream is used to be able to trim the elements before collecting them into a set
Set<String> userInput = Arrays.stream(textFieldContents .split(","))
.map(String::trim).collect(Collectors.toSet());
//stream the lines in the file
List<Boolean> matchResults = Files.lines(Path.of("areas.txt"))
//map each line to true/false
.map(line -> {
//split the line and stream the parts
return Arrays.stream(line.split(","))
//trim each part
.map(String::trim)
//select only those contained in the user input set
.filter(part -> userInput.contains(part))
//count matching elements and return whether there are more than 2 or not
.count() > 2l;
})
//collect the results into a list, each element position should correspond to the zero-based line number
.collect(Collectors.toList());
If you need to collect the matching lines instead of a flag per line you could replace map() with filter() (same content) and change the result type to List<String>.

How can I group strings based on their length?

public class sortingtext {
public static void main(String[] args) throws IOException {
String readline="i have a sentence with words";
String[] words=readline.split(" ");
Arrays.sort(words, (a, b)->Integer.compare(b.length(), a.length()));
for (int i=0;i<words.length;i++)
{
int len = words[i].length();
int t=0;
System.out.println(len +"-"+words[i]);
}
}
input:
i have a sentence with words
My code split a string and then it should print each word and their length.
The output I get looks like:
8- sentence
5- words
4- have
4-with
1-I
1-a
I want to group the words of same length to get that:
8- sentence
5- words
4- have ,with
1- I ,a
But I don't get how to group them.
Easy with the stream API:
final Map<Integer, List<String>> lengthToWords = new TreeMap<>(
Arrays.stream(words)
.collect(Collectors.groupingBy(String::length))
);
The stream groups the words by length into a map (implementation detail, but it will be a HashMap), the TreeMap then sorts this map based on the key (the word length).
Alternatively, you can write it like this which is more efficient but in my opinion less readable.
final Map<Integer, List<String>> lengthToWords = Arrays.stream(words)
.collect(Collectors.groupingBy(String::length, TreeMap::new, Collectors.toList()));
If you are a beginner or not familiar with stream API:
public static void main(String[] args) {
String readline= "i have a sentence with words";
String[] words = readline.split(" ");
Arrays.sort(words, (a, b)->Integer.compare(b.length(), a.length()));
// declare a variable to hold the current string length
int currLength = -1;
for(int i = 0; i<words.length; i++){
if(currLength == words[i].length()){
// if currLength is equal to current word length just append a comma and this word
System.out.print(", "+words[i]);
}
else{
// if not update currLength, jump to a new line and print new length with the current word
currLength = words[i].length();
System.out.println();
System.out.print(currLength+ " - "+words[i]);
}
}
}
Note: The println("...") method prints the string "..." and moves the cursor to a new line. The print("...") method instead prints just the string "...", but does not move the cursor to a new line. Hence, subsequent printing instructions will print on the same line. The println() method can also be used without parameters, to position the cursor on the next line.

How to get program to print the reverse of a word AFTER a hyphen?

I have the reverse part done, but I'm having trouble about the hyphen. Any help is appreciated! Also, the code so far.
public static void main(String[] args) {
Scanner kbd = new Scanner(System.in);
System.out.print( "Enter a string of words that contains a hyphen: ");
String word = kbd.next();
for (int i = word.length()-1; i >= 0; i--) {
System.out.print(word.charAt(i));
}
}
Example input:
low-budget
Required output:
tegdub (the reverse of the part after the hyphen)
This is the simplest possible solution I can think of (ofc there are other better solutions but this is my implementation:
public static void main(String[] args) {
Scanner kbd = new Scanner(System.in);
System.out.print( "Enter a string of words that contains a hyphen: ");
String word = kbd.next();
int loc = word.indexOf('-'); //Here I am trying to find the location of that hyphen
for (int i = word.length()-1; i > loc; i--) { //Now print the rest of the String in reverse TILL that location where we found hyphen. Notic i > loc
System.out.print(word.charAt(i));
}
System.out.print(" ");
for (int i = loc + 1; i < word.length(); i++) { //Now print the original String starting after the hyphen. Notice int i = loc + 1
System.out.print(word.charAt(i));
}
}
I would do it this way (in one line):
System.out.println(new StringBuilder(word.replaceAll(".*-", "")).reverse());
Edge cases handled for free:
If there's no hyphen, the whole string is printed reversed
If there's more than one hyphen, the last one is used. To use the first one, change the match regex to "^.*?-"
If the string is blank, a blank is printed
Think about all the code that didn't need to be written to handle these (valid) input cases
Breaking down how this works:
word.replaceAll(".*-", "") does a replacement of all matches to the regex .*-, which means "everything up to and including the (last) hyphen", with a blank - effectively deleting the match
new StringBuilder(...) creates a StringBuilder initialized with the String passed into the constructor (from point 1). The only reason we need a StringBuilder is to use the reverse() method (String doesn't have it)
reverse() reverses the StringBuilder's contents and returns it ready for the next call (see Fluent Interface)
Passing a non-String to System.out.println causes String.valueOf() to be invoked on the object, which in turn invokes the objects toString() method, which for a StringBuilder returns its contents
Voila!
Here's a (one-line) Java 8 stream-based solution for interest:
word.chars().skip(word.indexOf('-') + 1).mapToObj(c -> String.valueOf((char)c))
.reduce("", (a, b) -> b + a).ifPresent(System.out::println);
Edge case treatment:
Conveniently, if there's no hyphen, the whole string is printed in reverse. This is due to indexOf(char) returning -1 in the case of not found, so the end result is skipping zero (-1 + 1)
If more than one hyphen is present, only the first will be used to split the word
A blank string prints nothing, because the chars() stream is empty
To print a blank when the input is blank, use this code instead:
System.out.println(word.chars().skip(word.indexOf('-') + 1)
.mapToObj(c -> String.valueOf((char)c)).reduce("", (a, b) -> b + a));
Notice the use of the alternate form of the reduce() method, wherein an identity value of a blank ("") is passed in, which is used in the case of an empty stream to guarantee a reduction result.
First, split it based on the -.
Then, go over the second part in reverse...
String s = "low-budget";
String[] t = s.split("-");
for (int i = t[1].length() - 1; i >= 0; --i) {
System.out.print(t[1].charAt(i));
}

Having problems with a search method between Arrays and Array lists

OK so I'm trying to design a simple program that checks to see if a substring of length 4 characters is within all initial strings. Here is my code as follows:
public class StringSearch{
private String[] s1Array = {"A","C","T","G","A","C","G","C","A","G"};
private String[] s2Array = {"T","C","A","C","A","A","C","G","G","G"};
private String[] s3Array = {"G","A","G","T","C","C","A","G","T","T"};
//{for (int i = 0; i < s1Array.length; i++){
// System.out.print(s1Array[i]);
//}}//check if Array loaded correctly
/**
* This is the search method.
*
* #param length length of sub string to search
* #param count counter for search engine
* #param i for-loop counter
* #return subStr returns strings of length = 4 that are found in all 3 input strings with at most
* one mismatched position.
*/
public String Search()
{
int length = 4;
int count = 0;
int i = 0;
ArrayList<StringSearch> subStr = new ArrayList<StringSearch>();
//String[] subStr = new String[4];
do
{
for (i = count; i < length; i++){
subStr.add(s1Array[i]); // cant find .add method???
count = count + 1;
}
if (s2Array.contains(subStr) && s3Array.contains(subStr)){ //can't find .contains method???
System.out.println(subStr + "is in all 3 lists.");
}
if (count = s1Array.length){
System.out.println("Task complete.");
}
else{
count = count - length;
count = count + 1;
}
}while (count <= s1Array.length);
}
}
For some reason, Java cannot seem to find the .add or .contains methods and I have no idea why. So my approach was to turn the initial Strings each into an array (since the assignment specified each string would be exactly N elements long, in this case N = 10) where 1 letter would be 1 element. The next thing I did was set up a for loop that would scan s1Array and add the first 4 elements to an ArrayList subStr which is used to search s2Array and s3Array. Here is where .add isn't a valid method, for whatever reason. Commenting that out and compiling again, I also ran into an issue with the .contains method not being a valid method. Why won't this work? What am I missing? Logically, it seems to make sense but I guess maybe I'm missing something in the syntax? Help would be appreciated, as I'm a Java novice.
There are lots of errors and misunderstandings here.
Let's start with #1
private String[] s1Array = {"A","C","T","G","A","C","G","C","A","G"};
Making an array of strings is just silly, you should either use a single string or an array of characters.
private String s1 = "ACTGACGCAG";
Or
private char[] s1Array = {'A','C','T','G','A','C','G','C','A','G'};
Now #2
ArrayList<StringSearch> subStr = new ArrayList<StringSearch>();
This means you are trying to make an ArrayList that contains objects of type StringSearch. StringSearch is a class that contains your three arrays and your Search function so I don't think this is what you want.
If you wanted to make a list of 3 strings you might do something like this:
ArrayList<String> stringList = new ArrayList<String>();
stringList.add(s1);
stringList.add(s2);
stringList.add(s3);
Now say you defined s1, s2 and s3 as strings you can do something like this.
for(int i = 0; i <= s1.length() - 4; i++)
{
String subStr = s1.substring(i, i + 4);
if(s2.contains(subStr) && s3.contains(subStr))
{
System.out.println(subStr + " is in all 3 lists.");
}
}
System.out.println("Task Complete.");
The above code should achieve what it looks like you are trying to do. However, it should be noted that this isn't the most efficient way, just a way, of doing it. You should start with some more basic concepts judging by the code you have so far.
After declaring subStr as ArrayList you can call add or contains only with StringSearch objects as parameters.
Instead of:
ArrayList<StringSearch> subStr = new ArrayList<StringSearch>();
Replace it with:
String subStr = "";
And within the for loop to get the first 4 letters in s1 to be in its own string (subStr) add the line:
subStr += s1Array[i];
Also, s1Array is a String array, and not a String. The .contains method is a method that belongs to String variables, so for eg. the way you have it implemented, you can say s1Array[i].contains. But you cannot say s1Array.contains. If you change your String arrays to Strings and edit your code to suit, everything should work the way you expect it to work.
First of all you need to educate yourself on the concept of Java generics.
The most basic thing about generics is that once you declare a collection, here it is the arraylist, as you can only add objects of StringSearch.
Second of all, logically what you can do is to implement an algorithm called
Longest Common Subsequence. Check in pairs whether the longest subsequeces are 4 or not on the arrays.

Categories

Resources