Looping through List and creating views dependent on the data - java

I currently have two Lists:
List<String> listUserAnswers = splitWords(answer);
List<String> listRealAnswers = splitWords(realAnswer);
My main goal is to loop through these and create different views dependent on the data. For example, for each correctAnswer I will create one kind of view, and for incorrectAnswer, another.
I then loop through both the Lists:
for (String userAnswer : listUserAnswers) {
for (String realAnswer : listRealAnswers) {
if (userAnswer.equals(realAnswer)) {
correctLayout = createCorrectView(userAnswer);
newCorrectViews.add(correctLayout);
} else {
incorrectLayout = createIncorrectView(userAnswer);
newIncorrectViews.add(incorrectLayout);
}
}
}
I then check if the userAnswer matches the realAnswer, and then create the views.
However, the problem I'm experiencing is that if the realAnswer is:
[This, Is, The, Real, Answer]
and a user enters:
[This, Is, Real]
Then the first two words should show up on the screen as being correct, and the word 'Real' incorrect.
However, what's actually happening is:
[This, Is, This, This, Is, Is, Real, Real] -> where [This, Is] are correct and the rest are marked as incorrect.
Any ideas?

You shouldn't have an inner loop. You just need a loop for both so don't use an enhance one.
You can use something like:
minSize = listUserAnswers.size() > listRealAnswers.size() ? listUserAnswers.size() : listRealAnswers.size();
for(int i = 0; i < minSize; i++)
String userAnswer = listUserAnswers.get(i);
String realAnswer = listRealAnswers.get(i);
if(userAnswer.equals(realAnswer))
....
which just checks for the actual words in the same position.

Related

Character extract challenge

MY database value for bus column. 12,34,56,8,9, ... im trying to extract only the bus numbers and not the commas and adding them to a String ArrayList. Anyone have any idea? :
im really confuse. heres my code:
for(int i =0; i< buses1.length() ; i++ )
{
if(buses1.charAt(i) == ',')
{
}
else
{
bus1 += Character.toString(buses1.charAt(i));
buses.add(bus1);
}
}
at this point, the codes are adding like this, "1", "2" , "3" , "4" not "12", "34" ....
Any one have any ideal?
Get rid of your current logic. You just need String#split() with delimeter as "," which returns your bus numbers as a array.
The below line is enough
String[] numbers = columnValue.split(",");
Then your ArrayList delcaration turns
List<String> busesList = new ArrayList<String>(Arrays.asList(numbers));
All you have to do is to split the String by using the ',' delimiter.
List<String> buses = Arrays.asList(buses1.split(","));
EDIT: Make sure that by doing so, buses will be an unmodifiable list( a list where you cannot add/remove elements to/from it). If you need a modifiable list, you can easily wrap it into one :
List<String> buses = new LinkedList<String>(Arrays.asList(buses1.split(",")));
Other answers have explained the recommended what to solve this problem. I just want to point out why your current attempt fails.
To get the effect you describe, it must actually be something like this:
for (int i = 0; i < buses1.length(); i++ ) {
String bus1 = "";
if (buses1.charAt(i) == ',') {
} else {
bus1 += Character.toString(buses1.charAt(i));
buses.add(bus1);
}
}
The problem is that you are adding a "bus" to the list at the wrong point. You need to add it when you've got the last character of a (single- or multi-digit) bus number. But you are adding it for each digit.
Your code actually needs to be something like this:
String bus1 = "";
for (int i = 0; i < buses1.length(); i++ ) {
if (buses1.charAt(i) == ',') {
// When we see a comma, we know that is the end of the bus number.
if (!bus1.isEmpty()) {
buses.add(bus1);
bus1 = "";
}
} else {
// Accumulate the digits of the current bus number.
bus1 += Character.toString(buses1.charAt(i));
}
}
// Deal with stuff after the last comma.
if (!bus1.isEmpty()) {
buses.add(bus1);
}
Note that we could improve on that in a couple of important ways. But it is easier to see the relationship with your (hypothesized) original code with this version.

How can i extract specific terms from string lines in Java?

I have a serious problem with extracting terms from each string line. To be more specific, I have one csv formatted file which is actually not csv format (it saves all terms into line[0] only)
So, here's just example string line among thousands of string lines:
(split() doesn't work.!!! )
test.csv
"31451 CID005319044   15939353   C8H14O3S2    beta-lipoic acid   C1C[S#](=O)S[C##H]1CCCCC(=O)O "
"12232 COD05374044 23439353  C924O3S2    saponin   CCCC(=O)O "
"9048   CTD042032 23241  C3HO4O3S2 Berberine  [C##H]1CCCCC(=O)O "
I want to extract "beta-lipoic acid" ,"saponin" and "Berberine" only which is located in 5th position.
You can see there are big spaces between terms, so that's why I said 5th position.
In this case, how can I extract terms located in 5th position for each line?
One more thing: the length of whitespace between each of the six terms is not always equal. the length could be one, two, three, four, or five, or something like that.
Because the length of whitespace is random, I can not use the .split() function.
For example, in the first line I would get "beta-lipoic" instead "beta-lipoic acid.**
Here is a solution for your problem using the string split and index of,
import java.util.ArrayList;
public class StringSplit {
public static void main(String[] args) {
String[] seperatedStr = null;
int fourthStrIndex = 0;
String modifiedStr = null, finalStr = null;
ArrayList<String> strList = new ArrayList<String>();
strList.add("31451 CID005319044   15939353   C8H14O3S2 beta-lipoic acid C1C[S#](=O)S[C##H]1CCCCC(=O)O ");
strList.add("12232 COD05374044 23439353 C924O3S2 saponin CCCC(=O)O ");
strList.add("9048 CTD042032 23241 C3HO4O3S2 Berberine [C##H]1CCCCC(=O)O ");
for (String item: strList) {
seperatedStr = item.split("\\s+");
fourthStrIndex = item.indexOf(seperatedStr[3]) + seperatedStr[3].length();
modifiedStr = item.substring(fourthStrIndex, item.length());
finalStr = modifiedStr.substring(0, modifiedStr.indexOf(seperatedStr[seperatedStr.length - 1]));
System.out.println(finalStr.trim());
}
}
}
Output:
beta-lipoic acid
saponin
Berberine
Option 1 : Use spring.split and check for multiple consecutive spaces. Like the code below:
String s[] = str.split("\\s\\s+");
for (String string : s) {
System.out.println(string);
}
Option 2 : Implement your own string split logic by browsing through all the characters. Sample code below (This code is just to give an idea. I didnot test this code.)
public static List<String> getData(String str) {
List<String> list = new ArrayList<>();
String s="";
int count=0;
for(char c : str.toCharArray()){
System.out.println(c);
if (c==' '){
count++;
}else {
s = s+c;
}
if(count>1&&!s.equalsIgnoreCase("")){
list.add(s);
count=0;
s="";
}
}
return list;
}
This would be a relatively easy fix if it weren't for beta-lipoic acid...
Assuming that only spaces/tabs/other whitespace separate terms, you could split on whitespace.
Pattern whitespace = Pattern.compile("\\s+");
String[] terms = whitespace.split(line); // Not 100% sure of syntax here...
// Your desired term should be index 4 of the terms array
While this would work for the majority of your terms, this would also result in you losing the "acid" in "beta-lipoic acid"...
Another hacky solution would be to add in a check for the 6th spot in the array produced by the above code and see if it matches English letters. If so, you can be reasonably confident that the 6th spot is actually part of the same term as the 5th spot, so you can then concatenate those together. This falls apart pretty quickly though if you have terms with >= 3 words. So something like
Pattern possibleEnglishWord = Pattern.compile([[a-zA-Z]*); // Can add dashes and such as needed
if (possibleEnglishWord.matches(line[5])) {
// return line[4].append(line[5]) or something like that
}
Another thing you can try is to replace all groups of spaces with a single space, and then remove everything that isn't made up of just english letters/dashes
line = whitespace.matcher(line).replaceAll("");
Pattern notEnglishWord = Pattern.compile("^[a-zA-Z]*"); // The syntax on this is almost certainly wrong
notEnglishWord.matcher(line).replaceAll("");
Then hopefully the only thing that is left would be the term you're looking for.
Hopefully this helps, but I do admit it's rather convoluted. One of the issues is that it appears that non-term words may have only one space between them, which would fool Option 1 as presented by Hirak... If that weren't the case that option should work.
Oh by the way, if you do end up doing this, put the Pattern declarations outside of any loops. They only need to be created once.

How do I access and manipulate individual values in a String Array when using a while and for loop

Very new to Java: Trying to learn it.
I created an Array and would like to access individual components of the array.
The first issue I am having is how to I print the array as a batch or the whole array as indicated below? For example: on the last value MyValue4 I added a line break so that when the values are printed, the output will look like this: There has to be a better way to do this?
MyValue1
MyValue2
MyValue3
MyValue4
MyValue1
MyValue2
MyValue3
MyValue4
The next thing I need to do is, manipulate or replace a value with something else, example: MyValue with MyValx, when the repeat variable is at a certain number or value.
So when the repeat variable reaches 3 change my value to something else and then change back when it reaches 6.
I am familiar with the Replace method, I am just not sure how to put this all together.
I am having trouble with changing just parts of the array with the while and for loop in the mix.
My Code:
public static String[] MyArray() {
String MyValues[] = { "MyValue1", "MyValue2", "MyValue3", "MyValue4\n" };
return MyValues;
}
public static void main(String[] args) {
int repeat = 0;
while (repeat < 7) {
for (String lines : MyArray()) {
System.out.println(lines);
}
repeat = repeat + 1;
if (repeat == 7) {
break;
}
}
}
Maybe to use for cycle to be shorter:
for (int i = 0; i < 7; i++) {
for (String lines : MyArray()) {
// Changes depended by values.
if (i > 3) {
lines = MyValx;
}
System.out.println(lines); // to have `\n` effect
}
System.out.println();
}
And BTW variables will start in lower case and not end withenter (\n). So use:
String myValues[] = {"MyValue1", "MyValue2", "MyValue3", "MyValue4"};
instead of:
String MyValues[] = { "MyValue1", "MyValue2", "MyValue3", "MyValue4\n" };
and add System.out.println(); after eache inside cycle instead of this:
MyValues[n] = "value";
where n is the position in the array.
You may consider using System.out.println() without any argument for printing an empty line instead of inserting new-line characters in your data.
You already know the for-each loop, but consider a count-controlled loop, such as
for (int i = 0; i < lines.length; i++) {
...
}
There you can use i for accessing your array as well as for deciding for further actions.
Replacing array items based on a number in a string might be a bit trickier. A regular expression will definitely do the job, if you are familiar with that. If not, I can recommend learning this, because it will sure be useful in future situations.
A simpler approach might be using
int a = Integer.parseInt("123"); // returns 123 as integer
but that only works on strings, which contain pure numbers (positive and negative). It won't work with abc123. This will throw an exception.
These are some ideas, you might try out and experiment with. Also use the documentation excessively. ;-)

Executing code N times and other code N+1 times

The question is about while-loops in which I need some code to be executed N times and some other code N+1 times. NOT about concatening Strings, I just use this as bad-coded yet short example.
Let me explain my question by providing an example.
Say I want to concatenate N+1 Strings, by glueing them with "\n", for example. I will have N+1 lines of text then, but I only need to add N times "\n".
Is there any boilerplate solution for this type of loop in which you have to execute some code N times and other code N+1 times? I'm NOT asking for solution to concatenate Strings! That is just a (bad) example. I'm looking for the general solution.
The problem I have with this is code duplication, so to code my example I'll do this (bad pseudo code, I know I have to use StringBuilder etc.):
String[] lines = <some array of dimension N+1>;
String total = lines[0];
for (int i = 1; i < N + 1; i++){
total += "\n" + lines[i];
}
The problem becomes worse if the code that has to be executed N+1 times, becomes larger, of course. Then I would do something like
codeA(); // adding the line of text
for (int i = 1; i < N + 1; i++){
codeB(); // adding the "\n"
codeA();
}
To remove the duplication, you can do this different by checking inside the loop, too, but then I find this quite stupid as I know beforehand that the check is pre-determined, as it will only be false the first iteration:
for (int i = 0; i < N + 1; i++){
if (i > 0){
codeB(); // adding the "\n"
}
codeA();
}
Is there any solution for this, a sort of while-loop that initializes once with codeA() en then keeps looping over codeB() and codeA()?
People must have run into this before, I guess. Just wondering if there are any beautiful solutions for this.
To my dissapointment, I believe that there is no such construct that satisfies the conditions as you have stated them and I will attempt to explain why (though I can't prove it in a strictly mathematical way).
The requirements of the problem are:
We have two parts of code: codeA() and codeB()
The two parts are executed a different number of times, N and N+1
We want to avoid adding a condition inside the loop
We want to execute each part only as many times as strictly necessary
2) is a direct consequence of 1). If we didn't have two parts of code we would not need a different number of executions. We would have a single loop body.
4) is again a consequence of 1). There is no redundant execution if we have a single loop body. We can control its execution through the loop's condition
So the restrictions are basically 1) and 3).
Now inside the loop we need to answer two questions on each iteration: a) do we execute codeA()? and b) do we execute codeB()? We simply do not have enough information to decide since we only have a single condition (the condition of the loop) and that condition will be used to decide if both of the code parts would be executed or not.
So we need to break 1) and/or 3) Either we add the extra condition inside the loop or we delegate the decision to some other code (thus not having two parts anymore).
Apparently an example of delegation could be (I am using the string concatenation example):
String [] lines = ...
for (int i = 0; i < N; i++){
// delegate to a utility class LineBuilder (perhaps an extension of StringBuilder) to concatenate lines
// this class would still need to check a condition e.g. for the first line to skip the "\n"
// since we have delegated the decisions we do not have two code parts inside the loop
lineBuilder.addLine( lines[i] );
}
Now a more interesting case of delegation would be if we could delegate the decision to the data itself (this might worth keeping in mind). Example:
List<Line> lines = Arrays.asList(
new FirstLine("Every"), // note this class is different
new Line("word"),
new Line("on"),
new Line("separate"),
new Line("line") );
StringBuffer sb = new StringBuffer();
for (Line l : lines) {
// Again the decision is delegated. Data knows how to print itself
// Line would return: "\n" + s
// FirstLine would return: s
sb.append( l.getPrintVersion() );
}
Of course all of the above does not mean that you couldn't implement a class that tries to solve the problem. I believe though this is beyond the scope of your original question not to mention that would be an overkill for simple loops
Concatenating Strings like this is a bad idea and a much bigger issue IMHO.
However to answer your question I would do
String sep = "";
StringBuilder sb= new StringBuilder();
for(String s: lines) {
sb.append(sep).append(s);
sep = "\n";
}
String all = sb.toString();
Note: there is usually a good way to avoid needing to create this String at all such a processing the lines as you get them. It is hard to say without more context.
This kind of thing is fairly common, like when you build sql. This is the pattern that I follow:
String[] lines ...//init somehow;
String total = lines[0];
boolean firstTime = true;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++){
if(firstTime) firstTime = false;
else sb.append('\n');
sb.append(lines[i]);
}
Note that this is not the same, as the first example and here is why:
String[] lines = <some array of dimension N+1>;
String total = lines[0];
for (int i = 1; i < N + 1; i++){
total += "\n" + lines[i];
}
Assuming you have an array of [0] = 'line1' and [1] = 'line2'
Here you end up with line1line2\n, when the desired output is:
line1\nline2.
The example I provided is clear, and does not perform poorly. In fact a much bigger performance gain is made by utilizing StringBuilder/Buffer. Having clear code is essential for the pro.
Personally i have most of the time the same problem, on the String example i use the StringBuilder as you said, and just delete the characters added to much:
StringBuilder sb = new StringBuilder();
for(int i=0; i<N; i++) {
sb.append(array[i]).append("\n");
}
sb.delete(sb.length-1, sb.length); // maybe check if sb contains something
In the common case i suppose there is no other way than adding the if you suggested. To make the code more clear i would check at the end of the for loop:
StringBuilder sb = new StringBuilder();
for(int i=0; i<N; i++) {
sb.append(array[i]);
if(i < N) {
sb.append("\n");
}
}
But i totally agree this is sad to have this double logic

Determining if a given string of words has words greater than 5 letters long

So, I'm in need of help on my homework assignment. Here's the question:
Write a static method, getBigWords, that gets a String parameter and returns an array whose elements are the words in the parameter that contain more than 5 letters. (A word is defined as a contiguous sequence of letters.) So, given a String like "There are 87,000,000 people in Canada", getBigWords would return an array of two elements, "people" and "Canada".
What I have so far:
public static getBigWords(String sentence)
{
String[] a = new String;
String[] split = sentence.split("\\s");
for(int i = 0; i < split.length; i++)
{
if(split[i].length => 5)
{
a.add(split[i]);
}
}
return a;
}
I don't want an answer, just a means to guide me in the right direction. I'm a novice at programming, so it's difficult for me to figure out what exactly I'm doing wrong.
EDIT:
I've now modified my method to:
public static String[] getBigWords(String sentence)
{
ArrayList<String> result = new ArrayList<String>();
String[] split = sentence.split("\\s+");
for(int i = 0; i < split.length; i++)
{
if(split[i].length() > 5)
{
if(split[i].matches("[a-zA-Z]+"))
{
result.add(split[i]);
}
}
}
return result.toArray(new String[0]);
}
It prints out the results I want, but the online software I use to turn in the assignment, still says I'm doing something wrong. More specifically, it states:
Edith de Stance states:
⇒     You might want to use: +=
⇒     You might want to use: ==
⇒     You might want to use: +
not really sure what that means....
The main problem is that you can't have an array that makes itself bigger as you add elements.
You have 2 options:
ArrayList (basically a variable-length array).
Make an array guaranteed to be bigger.
Also, some notes:
The definition of an array needs to look like:
int size = ...; // V- note the square brackets here
String[] a = new String[size];
Arrays don't have an add method, you need to keep track of the index yourself.
You're currently only splitting on spaces, so 87,000,000 will also match. You could validate the string manually to ensure it consists of only letters.
It's >=, not =>.
I believe the function needs to return an array:
public static String[] getBigWords(String sentence)
It actually needs to return something:
return result.toArray(new String[0]);
rather than
return null;
The "You might want to use" suggestions points to that you might have to process the array character by character.
First, try and print out all the elements in your split array. Remember, you do only want you look at words. So, examine if this is the case by printing out each element of the split array inside your for loop. (I'm suspecting you will get a false positive at the moment)
Also, you need to revisit your books on arrays in Java. You can not dynamically add elements to an array. So, you will need a different data structure to be able to use an add() method. An ArrayList of Strings would help you here.
split your string on bases of white space, it will return an array. You can check the length of each word by iterating on that array.
you can split string though this way myString.split("\\s+");
Try this...
public static String[] getBigWords(String sentence)
{
java.util.ArrayList<String> result = new java.util.ArrayList<String>();
String[] split = sentence.split("\\s+");
for(int i = 0; i < split.length; i++)
{
if(split[i].length() > 5)
{
if(split[i].matches("[a-zA-Z]+"))
{
result.add(split[i]);
}
if (split[i].matches("[a-zA-Z]+,"))
{
String temp = "";
for(int j = 0; j < split[i].length(); j++)
{
if((split[i].charAt(j))!=((char)','))
{
temp += split[i].charAt(j);
//System.out.print(split[i].charAt(j) + "|");
}
}
result.add(temp);
}
}
}
return result.toArray(new String[0]);
}
Whet you have done is correct but you can't you add method in array. You should set like a[position]= spilt[i]; if you want to ignore number then check by Float.isNumber() method.
Your logic is valid, but you have some syntax issues. If you are not using an IDE like Eclipse that shows you syntax errors, try commenting out lines to pinpoint which ones are syntactically incorrect. I want to also tell you that once an array is created its length cannot change. Hopefully that sets you off in the right directions.
Apart from syntax errors at String array declaration should be like new String[n]
and add method will not be there in Array hence you should use like
a[i] = split[i];
You need to add another condition along with length condition to check that the given word have all letters this can be done in 2 ways
first way is to use Character.isLetter() method and second way is create regular expression
to check string have only letter. google it for regular expression and use matcher to match like the below
Pattern pattern=Pattern.compile();
Matcher matcher=pattern.matcher();
Final point is use another counter (let say j=0) to store output values and increment this counter as and when you store string in the array.
a[j++] = split[i];
I would use a string tokenizer (string tokenizer class in java)
Iterate through each entry and if the string length is more than 4 (or whatever you need) add to the array you are returning.
You said no code, so... (This is like 5 lines of code)

Categories