Using 1 loop instead of 6 in Java - java

#When("User fetches the sms template from the templates fetched")
public void user_fetches_the_sms_template_from_the_templates_fetched() {
List<String> jsonResponse = response.jsonPath().getList("$");
for (int i = 0; i < jsonResponse.size(); i++) {
if (getJsonPath(response, "type[" + i + "]").equals("agent_sms_missed_call")) {
agentMissedCallId = getJsonPath(response, "id[" + i + "]");
break;
}
}
for (int i = 0; i < jsonResponse.size(); i++) {
if (getJsonPath(response, "type[" + i + "]").equals("caller_sms_missed_call")) {
callerMissedCallSmsId = getJsonPath(response, "id[" + i + "]");
break;
}
}
for (int i = 0; i < jsonResponse.size(); i++) {
if (getJsonPath(response, "type[" + i + "]").equals("agent_sms_received_call")) {
agentReceivedCallSmsId = getJsonPath(response, "id[" + i + "]");
break;
}
}
for (int i = 0; i < jsonResponse.size(); i++) {
if (getJsonPath(response, "type[" + i + "]").equals("caller_sms_received_call")) {
callerReceivedCallSmsId = getJsonPath(response, "id[" + i + "]");
break;
}
}
for (int i = 0; i < jsonResponse.size(); i++) {
if (getJsonPath(response, "type[" + i + "]").equals("answered_on_ivr_sms")) {
answeredOnIvrSmsId = getJsonPath(response, "id[" + i + "]");
break;
}
}
for (int i = 0; i < jsonResponse.size(); i++) {
if (getJsonPath(response, "type[" + i + "]").equals("answered_on_auto_attendant_sms"))
{
answeredOnAaSmsId = getJsonPath(response, "id[" + i + "]");
break;
}
}
}
Instead of using 6 loops i want to achieve in 1 loop and 6 flag variable so that it goes in IF condition only once. How can i achieve he same ? I am using this rest assured api automation testing.

I'm not familiar with JSON or REST-Assured. My response will reflect that. Also, my response will reflect what my nickname (user name) suggests.
The for loop statements are all the same: for (int i = 0; i < jsonResponse.size(); i++). Assuming nothing done inside the loop changes jsonResponse, you should be able to condense them into one:
#When("User fetches the sms template from the templates fetched")
public void user_fetches_the_sms_template_from_the_templates_fetched() {
List<String> jsonResponse = response.jsonPath().getList("$");
for (int i = 0; i < jsonResponse.size(); i++) {
if (getJsonPath(response, "type[" + i + "]").equals ("agent_sms_missed_call")) {
agentMissedCallId = getJsonPath(response, "id[" + i + "]");
}
if (getJsonPath(response, "type[" + i + "]").equals ("caller_sms_missed_call")) {
callerMissedCallSmsId = getJsonPath(response, "id[" + i + "]");
}
// and 4 more similar if ( ...
This ignores the break statements in each if block of the original code. That might be acceptable. But, it would help to know why the break statements are there.
For efficiency? Once all 6 matches are found, there is no need to continue the loop. This could be important if jsonResponse.size() is large. If small, it's not important.
Is there the possibility of duplicates? If so, is it important to find only the first match?
Other?
If "first match" is required, and jsonResponse.size() is small enough, the "first match" criterion could be preserved by running the for loop with decrement:
for (int i = jsonResponse.size() - 1; i >= 0; i--)
Another suggestion:
#When("User fetches the sms template from the templates fetched")
public void user_fetches_the_sms_template_from_the_templates_fetched() {
List<String> jsonResponse = response.jsonPath().getList("$");
boolean agentMissSet, callerMissSet, agentReceiveSet, callerRecieveSet;
boolean answeredIvrSet, answeredAAset;
agentMissSet = callerMissSet = agentReceiveSet = callerRecieveSet
= answeredIvrSet = answeredAAset = false;
for (int i = 0; i < jsonResponse.size(); i++) {
if (( ! agentMissSet) &&
getJsonPath(response, "type[" + i + "]").equals ("agent_sms_missed_call")) {
agentMissedCallId = getJsonPath(response, "id[" + i + "]");
agentMissSet = true;
}
if (( ! callerMissedSet) &&
getJsonPath(response, "type[" + i + "]").equals ("caller_sms_missed_call")) {
callerMissedCallSmsId = getJsonPath(response, "id[" + i + "]");
callerMissSet = true;
}
// and four more similar if (...
This address the possibility of duplicates issue but not the efficiency issue, if jsonResponse.size() is large. To fix the efficiency issue, add this just before the closing } of the for loop code block:
if ( agentMissSet && callerMissSet && agentReceiveSet
&& callerRecieveSet && answeredIvrSet && answeredAAset ) break;
I don't know what the values of agentMissedCallId, callerMissedCallSmsId, and the other 4 are before the for loop. If they are null or empty, or have some other common default value, that could be used instead of the 6 boolean. This example assumes they will be null:
for (int i = 0; i < jsonResponse.size(); i++) {
if ( agentMissedCallId != null &&
getJsonPath(response, "type[" + i + "]").equals ("agent_sms_missed_call")) {
agentMissedCallId = getJsonPath(response, "id[" + i + "]");
// and 5 more similar ...
That assumes getJsonPath is not going to return null, empty, or whatever is used for the "already set test".
The replacement of the if statement testing 6 boolean, if used, would be an if statement testing 6 String against null, empty, or other default value.
One problem I see with my suggested changes is that the code seems to have gotten uglier. And the 6 if statement and blocks have almost the same code. When I see occurrences of same code, one thing I think of is arrays. Here is how to use two for loops, and arrays:
#When("User fetches the sms template from the templates fetched")
public void user_fetches_the_sms_template_from_the_templates_fetched() {
List<String> jsonResponse = response.jsonPath().getList("$");
String [] id = { agentMissedCallId , callerMissedCallSmsId ,
agentReceivedCallSmsId , callerReceivedCallSmsId ,
answeredOnIvrSmsId , answeredOnAaSmsId
};
String [] type = {"agent_sms_missed_call" , "caller_sms_missed_call",
"agent_sms_received_call" , "caller_sms_received_call",
"answered_on_ivr_sms" , "answered_on_auto_attendant_sms"
};
for (int j = 0; j < id.length; j++) {
for (int i = 0; i < jsonResponse.size (); i++) {
if (getJsonPath(response, "type[" + i + "]").equals(type[j])) {
id [j] = getJsonPath(response, "id[" + i + "]");
break;
}
}
}
}
The above assumes jsonResponse.size() is small, and it's not unreasonable iterate through it 6 times.
The following has the loops nested in the opposite order:
#When("User fetches the sms template from the templates fetched")
public void user_fetches_the_sms_template_from_the_templates_fetched() {
List<String> jsonResponse = response.jsonPath().getList("$");
String [] id = { agentMissedCallId , callerMissedCallSmsId ,
agentReceivedCallSmsId , callerReceivedCallSmsId ,
answeredOnIvrSmsId , answeredOnAaSmsId
};
String [] type = {"agent_sms_missed_call" , "caller_sms_missed_call",
"agent_sms_received_call" , "caller_sms_received_call",
"answered_on_ivr_sms" , "answered_on_auto_attendant_sms"
};
boolean [] matchFound = new boolean [6];
int matchCount = 0;
Arrays.fill (matchFound, false);
for (int i = 0; i < jsonResponse.size () && matchCount < 6; i++) {
for (int j = 0; j < id.length; j++) {
if (matchFound[j]) { continue; }
if (getJsonPath(response, "type[" + i + "]").equals(type[j])) {
id [j] = getJsonPath(response, "id[" + i + "]");
matchFound [j] = true;
matchCount++;
}
}
}
}
Notes:
I assumed getJsonPath returns a String. If it returns some other type of Object, use that type for the id array.
Having tightly coupled arrays suggests room for improvement. Consider having a helper class in which each instance has one id, one type and maybe one matchFound. That way, you can have one array.
I responded to the question in the header: How to reduce the number of for loops. I suspect the code can be improved by making jsonResponse some other Collection, possibly a Map. But, in my judgement, that would be off-topic. Also, I lack sufficient information to be able to elaborate. Perhaps the O/P could followup with a new question. The new question could have some explanation of what the code is to accomplish, and reference this question.
This answer lacks focus. This is the result of several "unknowns". Rather than asking the O/P several questions via the question comments, I attempted to cover several unknowns in a single answer. If the O/P provides more information, I can delete parts of this answer that would then become irrelevant, and otherwise improve this answer.
Another factor in making the answer long is that it is an attempt to show how I might think about this problem.

Related

How to print a string formatted properly

I am doing Test Driven Development.So I created a case that needs to send an array of strings to the function.That function will check if the array has any uppercase letter strings.If there is then it needs to print all the strings as "name , name, name and name are amazing".So before the last one it should be putting an "and".
It is sometimes giving me dead code error because there are other cases that might be interfering with the execution of this case.
Test Case
#Test
void testAcceptsAJumbleOfUpperCaseAndLowerCase() {
theAmazingPeter obj = new theAmazingPeter();
String[] arr = {"Peter","GUNEET"};
String result = obj.AmazingPerson(arr);
assertEquals("Peter, and GUNEET are amazing",result);
}
}
Statement
else {
for (int i = 0; i < names.length; i++) {
if (names.length >= 1 && names[i].equals(names[i].toUpperCase())) {
if (i > 0) {
sb.append(", ");
if (i == names.length - 1) {
sb.append("and ");
}
}
sb.append(names[i]);
}
System.out.println(sb.toString() + " are amazing");
}
String result = sb.toString() + " are amazing";
return result;
}
If it is needed to check if the string contains capital letter, it will need to be implemented as following:
StringBuffer sb = new StringBuffer();
char ch;
for (int i = 0; i < names.length; i++) {
if (Character.isUpperCase(names[i].charAt(0))) {
if (i == names.length - 1) {
sb.append(" and " + names[i]);
} else if (i == names.length - 2) {
sb.append(names[i]);
} else {
sb.append(names[i] + ", ");
}
}
}
System.out.println(sb.toString() + " are amazing");
String result = sb.toString() + " are amazing";
return result;
This line in your code is wrong:
if(names.length >= 1 && names[i].equals(names[i].toUpperCase()))
This if statement comes true only when all the letters of string are capital letters.
For example: if names[i] contains "Peter" then names[i].toUpperCase() equals "PETER" and the expression will return false. But what you want is accepting this string because it contains capital letter.
Instead doing this, you can use Character.isUpperCase(char) method.
public boolean containsUpper(String s){
for (int i = 0 ; i< s.length(); i++){
if(Character.isUpperCase(s.charAt(i)))
return true;
}
return false;
}
You may call this function for every string then continue.

How to make a String from two set of list with alternate values

I have two lists which contains some values,I have to make String from them so that i will take the 1st value of first list and 1 st value of 2 nd list and also 2nd value of first list and 2 nd value of 2nd list and so on..Lets says those two lists contains the interview timings.So i am giving my code here
List<String> interviewTimingToFrom1 = Arrays.asList(interviewTime1.split(","));
for(String a :interviewTimingToFrom1){
System.out.println("Timing 1:"+a);
}
List<String> interviewTimingToFrom2 = Arrays.asList(interviewTime2.split(","));
for(String a :interviewTimingToFrom2){
}
The values contain in the 1 st and 2nd list are
Timing 1:12:00am
Timing 1:2:00am
Timing 2:1:00am
Timing 2:3:00am
So now i need to make a string like from 12.00am to 1.00 am ,from 2.00 am to 3.00am how i can do that .Please help
int maxSize = Math.max(interviewTimingToFrom1.size(),interviewTimingToFrom2.size());
StringBuilder result = new StringBuilder();
for (int i=0; i<maxSize; i++)
{
if (i < interviewTimingToFrom1.size())
result.append(interviewTimingToFrom1.get(i));
if (i < interviewTimingToFrom2.size())
result.append(interviewTimingToFrom2.get(i));
}
System.out.println(result.toString());
Try this;
List<String> interviewTimingToFrom1 = Arrays.asList(interviewTime1.split(","));
List<String> interviewTimingToFrom2 = Arrays.asList(interviewTime2.split(","));
if (interviewTimingToFrom1.size() == interviewTimingToFrom2.size()) {
int noOfSlots = interviewTimingToFrom1.size();
for (int i = 0; i < noOfSlots; i++) {
System.out.println("from " + interviewTimingToFrom1.get(i)
+ " to " + interviewTimingToFrom1.get(i));
}
} else {
System.out.println("No match");
int noOfSlots = (interviewTimingToFrom1.size() > interviewTimingToFrom2
.size() ? interviewTimingToFrom2.size()
: interviewTimingToFrom1.size());
for (int i = 0; i < noOfSlots; i++) {
System.out.println("from " + interviewTimingToFrom1.get(i)
+ " to " + interviewTimingToFrom2.get(i));
}
}

No Such Element Exception With Loop

I am using this code, and for some reason, I'm getting a No Such Element Exception...
numCompanies is being imported from the keyboard and is showing up right and portfolio is an array with [numCompanies][4].
Can anyone figure out why?
for(int i = 0; i < numCompanies; i++)
{
System.out.print("Stock #" + (i+1) + ": ");
String stockData = kbReader.nextLine();
System.out.print("\n\n hi" + stockData);
Scanner stockLine = new Scanner(stockData);
for(int j = 0; j < 4; j++)
{
portfolio[i][j] = stockLine.next();
}
}
I have not tested this but probably stockLine.next(); is called even though there is no element left. So maybe this could help:
for(int j = 0; j < 4; j++)
{
if( stockLine.hasNext() ) {
portfolio[i][j] = stockLine.next();
}
else
{
portfolio[i][j] = 0; // or whatever you want it to be by default
}
}
This will solve the error message but not the fault.
You're passing a single string to a Scanner object, but I would say there's a better way of doing this.
If you want to simply read in the input for each value in the string, separated by spaces, then use split():
String stockData = kbReader.nextLine();
String[] data = stockData.split(" ");
if (data.length != 4) {
System.err.println("Bad data value found!");
} else {
//run your loop
}

Search function adding an index on each new line

So I have been writing a chat client and I decided to make a search function so you could find a particular word in the chat history and it selects it. However, what happens is that each line below the initial line the selection is that many indexes right of the word it should select. Is there a new line character or index locations I am missing?
How do I get around the indexes changing on each line?
Or perhaps there is an issue in my code:
private void nextButtonActionPerformed(java.awt.event.ActionEvent evt) {
toSearchText = searchText.getText();
if (!toSearchText.equals("")) {
for (int i = index; i < searchBlock.length(); i++) {
if (searchBlock.charAt(i) == toSearchText.charAt(0)) {
System.out.println("found first char- Starting check loop." + i + j + "::" + count);
for (j = i; j < i + toSearchText.length(); j++) {
System.out.println("J" + j + " II " + innerIndex);
if (searchBlock.charAt(j) == toSearchText.charAt(innerIndex)) {
innerIndex++;
count++;
System.out.println("found char:" + innerIndex + " - " + searchBlock.charAt(j));
} else {
System.out.println("Not the word");
break;
}
}
}
System.out.println(i);
System.out.println(j);
if (count == toSearchText.length()) {
if (searchBlock.substring(i, j).equals(toSearchText)) {
System.out.println(searchBlock.substring(i, j) + " and " + toSearchText);
System.out.println("focusing");
ClientWindow.mainText.requestFocusInWindow();
ClientWindow.mainText.select(i, j);
count = 0;
innerIndex = 0;
index = i + toSearchText.length();
if (index > searchBlock.length()) {
index = 0;
}
break;
}
} else {
System.out.println("focus refused");
}
}
System.out.println("Search Finished");
}
}
Ok, So to get around the issue of there being an extra index on each line, I wrote a method to count the lines and then minused that value from the indexes.
private int checkLine(int position){
int counter = 0;
Scanner text = new Scanner(searchBlock.substring(0,position));
while(text.hasNextLine()){
counter++;
text.nextLine();
}
return counter - 1;
}

Reflection of an array in java

I'm fairly new to java and have come across a problem. My task is to create a class which contains a method write(Object obj) that writes the type of the object as well as the name and type of all attributes into a file. Recursion is involved since the object may have objects/arrays of objects as attributes.
Here is the code:
public void write(Object obj) throws Exception {
if(obj == null)
{
out.close();
return;
}
Class c = obj.getClass();
Class d;
Field fields_c[] = c.getDeclaredFields();
System.out.println("class_name:" + c.getName());
int i, j;
String tab = new String("");
for(i = 0; i < indent_level; i++)
{
tab = tab + "\t";
}
out.write(tab + "class_name:" + c.getName() + "\n");
for(i = 0; i < fields_c.length; i++) {
System.out.println("field name: " + fields_c[i].getName() + " ");
c = fields_c[i].getType();
fields_c[i].setAccessible(true);
if(c.isPrimitive()) {
out.write("\t" + tab + "field_name:" + c.toString() + "\n");
}
else if(c.isArray()) {
System.out.println("field of type array with elements of type:" + c.getComponentType());
for(j = 0; j < Array.getLength(c); j++)
{
d = Array.get(c, j).getClass();
indent_level = indent_level + 1;
this.write(d);
indent_level = indent_level - 1;
}
}
else
{
System.out.println("field is not primitive of type:" + c.getName());
Object foo = fields_c[i].get(obj);
indent_level = indent_level + 1;
this.write(foo);
indent_level = indent_level - 1;
}
}
}
An exception arises if I call the method and give an Object that has an array attribute; all attributes until the array are written properly to the output file.
The exception is "java.lang.IllegalArgumentException: Argument is not an array".
In d = Array.get(c, j).getClass(); c is of type java.lang.Class, but an array is expected.
You should change it to d = Array.get(fields_c[i].get(obj), j) and use c#getComponentType for get the type of the array.
This may not be what you're after, but if this is to do with serialisation then I recommend "Simple";
http://simple.sourceforge.net/
It makes Java <=> XML serialisation unbelievably easy.
Why you're passing Class of elements instead of elements:
Object[] array = fields_c[i].get(obj);
for(j = 0; j < Array.getLength(array); j++)
{
Object foo = Array.get(array, j); // not .getClass()
indent_level = indent_level + 1;
this.write(foo);
indent_level = indent_level - 1;
}

Categories

Resources