This question is more about best practice than about fetching elements from a list.
I have an ArrayList which I am itaration though by using a simple for-loop. In case a certain keyword shows up, I need to compare the next tree elements to a certain pattern.
private static boolean areVectorArgumentsValid(ArrayList<String> fileContent)
{
for (int i=0; i<fileContent.size(); i++)
{
if (fileContent.get(i).equals(NORMAL) || fileContent.get(i).equals(VERTEX))
{
// get the next three elements of "fileContent" and see if they match a certain pattern
}
}
return true;
}
My first approach would be to use another for-loop within the actual outler loop and then increment i by 3:
for (int j=i+1; j<=i+3; j++)
{
if (!fileContent.get(j).matches(PATTERN))
{
return false;
}
}
i+=3;
As you see, it is not hard to make the method do what I want it to do, but... I am not sure if there might be a way which you'd call more elegant.
This question is more about best practice than about fetching elements
from a list.
Before going into details few remarks..
NORMAL.equals(fileContent.get(i)) instead of fileContent.get(i).equals(NORMAL) will avoid NullPointerException
Before iterating for next three element you should first check whether your List has next three element or not to avoid ArrayIndexOutOfBoundException
Now If it's about checking for only next three elements and only return false if any of the three element does not match the pattern than you can have something like following,
if (fileContent.size() < i + 3
&& (!fileContent.get(i+1).matches(PATTERN)
|| !fileContent.get(i+2).matches(PATTERN)
|| !fileContent.get(i+3).matches(PATTERN))) {
return false;
}
Problem in this approach is it will not check if your list does not have next three elements.
As for your approach by allowing check of next available elements you can just add one condition to check whether your list has next element or not in loop before calling get method on the list.Your approach to iterate over next three element seems fine but following improvement is needed.
for (int j=i+1; j<=i+3; j++){
if (fileContent.size() < j && !fileContent.get(j).matches(PATTERN)){
return false;
} else {
break;
}
}
In my opinion you should make a method, that takes the array and index to start looking from, and return boolean if it match the three or not. It is the elegant way.
You can do it with just one loop by introducing a state :
private static boolean areVectorArgumentsValid(ArrayList<String> fileContent)
{
int state = 0;
for (int i=0; i<fileContent.size(); i++)
{
switch (state) {
case 0:
if (fileContent.get(i).equals(NORMAL) || fileContent.get(i).equals(VERTEX))
state++;
break;
case 1:
case 2:
case 3:
if (!fileContent.get(i).matches(PATTERN))
return false;
state = (state + 1) % 4;
break;
}
return true;
}
You could repeat three times and use ++i when getting the element:
for (int j = 0; j < 3; j++) {
if (!fileContent.get(++i).matches(PATTERN)) {
return false;
}
}
Or do something like this with stream:
if (fileContent.stream().skip(i).limit(3).anyMatch(s -> !s.matches(PATTERN))) {
return false;
}
i += 3;
But I think the best solution would be completely changing it and using an Iterator:
private static boolean areVectorArgumentsValid(ArrayList<String> fileContent) {
for (Iterator<String> it = fileContent.iterator(); it.hasNext();) {
String s = it.next();
if (!s.equals(NORMAL) && !s.equals(VERTEX)) {
continue;
}
for (int i = 0; i < 3; i++) {
if (!it.hasNext() || !it.next().matches(PATTERN)) {
return false;
}
}
}
return true;
}
Related
Folks, my method needs to add a new element into already a sorted list, i.e. in a proper position. The point is the method checks the lowest row index and then compares its cols. For example,
board.set(2,2, 11);
board.set(-1,0,22);
board.set(-1,2,33);
board.set(1,0,44);
board.set(3,0,55);
board.set(3,1,66);
board.set(3,3,77);
board.set(3,2,88);
board.set(-1,1,99);
The result should be:
[(-1,0,22), (-1,1,99), (-1,2,33), (1,0,44), (2,2,11), (3,0,55), (3,1,66), (3,2,88), (3,3,77)]
But my program prints this:
[(-1,0,22), (-1,1,99), (3,2,88), (3,3,77), (3,1,66), (3,0,55), (1,0,44), (-1,2,33), (2,2,11)]
i.e. it does not put the objects into the proper positions.
I have a LinkedList<RowColElem<T>>rowColSeq where the objects are added and put into a proper position "on the go". What is my code missing?
NOTE: Im not allowed to use comparators, comparable interface!
LinkedList<RowColElem<T>> rowColSeq; // Is not empty, already contains objects!
private void sortedRowColSeq(int row, int col, T x){
RowColElem<T> object = new RowColElem<T>(row, col, x);
ListIterator<RowColElem<T>> iter = rowColSeq.listIterator();
RowColElem<T> inListObject;
boolean added = false;
while(iter.hasNext()){
inListObject = iter.next();
if(object.getRow() < inListObject.getRow()){
iter.previous();
iter.add(object);
undoStack.push(object);
added = true;
break;
}
else if(object.getRow() == inListObject.getRow()){
if(object.getCol() < inListObject.getCol()){
iter.previous();
iter.add(object);
undoStack.push(object);
added = true;
}
}
else{
iter.add(object);
undoStack.push(object);
added = true;
break;
}
}
}
You may not add if the new element is greater than some element. You must enter before one that is greater, or at the end.
boolean added = false;
while(iter.hasNext()){
inListObject = iter.next();
if(object.getRow() < inListObject.getRow() ||
object.getRow() == inListObject.getRow()) &&
object.getCol() < inListObject.getCol() ){
if( iter.hasPrevious() ){
iter.previous();
iter.add(object);
} else {
rowColSeq.addFirst( object );
}
undoStack.push(object);
added = true;
break;
}
}
if( ! added ){
rowColSeq.addLast(object);
undoStack.push(object);
added = true;
}
The approach using iter.previous() is doomed to fail under certain circumstances so I added a test and alternative code.
public static ArrayList<ArrayList<HSSFCell>> newTogether(ArrayList<ArrayList<HSSFCell>> sheetData) {
ArrayList<ArrayList<HSSFCell>> temporary = new ArrayList<ArrayList<HSSFCell>>();
for(int i = 0; i < sheetData.size(); i++) {
ArrayList<HSSFCell> list = sheetData.get(i);
if (list.get(3).getCellType() == Cell.CELL_TYPE_NUMERIC) {
if(Integer.parseInt(list.get(3).getStringCellValue()) > 100) {
temporary.add(list);
sheetData.remove(i);
i--;
}
}
}
for(int i = 0; i < sheetData.size(); i++) {
ArrayList<HSSFCell> list = sheetData.get(i);
temporary.add(list);
}
return temporary;
}
What I am trying to do with my code is have the 2D ArrayList take out any numbers greater than 100 and put them in the beginning of the ArrayList, while preserving the order of the remaining elements. However, this code just returns an ArrayList in the original order, and if I add a println to either if, I get nothing. Could someone point out what it is I'm doing wrong?
Have you tried putting a println in front of the first if to check what getStringCellValue() returns?
btw. since Collections.sort is guaranteed to be stable according to the API documentation, you could use that. Should be faster than your way of doing it.
That could look like this
private static boolean biggerThan100(ArrayList<HSSFCell> list) {
return list.get(3).getCellType() == Cell.CELL_TYPE_NUMERIC &&
(Integer.parseInt(list.get(3).getStringCellValue()) > 100);
}
public static ArrayList<ArrayList<HSSFCell>> newTogether(ArrayList<ArrayList<HSSFCell>> sheetData) {
ArrayList<ArrayList<HSSFCell>> temp = new ArrayList<>(sheetData);
Collections.sort(temp, new Comparator<ArrayList<HSSFCell>>() {
public int compare(ArrayList<HSSFCell> a, ArrayList<HSSFCell> b) {
if(biggerThan100(a) && !biggerThan100(b)) return -1;
else if(biggerThan100(b) && !biggerThan100(a)) return 1;
else return 0;
}
});
return temp;
}
I've been working on an algorithm to loop through one ArrayList containing a custom object. I'm now on hour 20 and I've gotten almost nowhere.
ArrayList<TicketItem> all = new ArrayList<>();
// ... 'all' gets filled here ... //
ArrayList<TicketItem> allCopy = new ArrayList<>(all);
for (int i = allCopy.size() - 1; i > 0; i--) {
TicketItem last = allCopy.get(i);
for (int j = 0; j < all.size(); j++) {
TicketItem compare = all.get(j);
if (last.getInt(TicketItem.TICKET_ITEM_ID) != compare.getInt(TicketItem.TICKET_ITEM_ID)) {
if (last.canBeGrouped(compare)) {
last.put(TicketItem.TICKET_ITEM_NUMBER, compare.getInteger(TicketItem.TICKET_ITEM_NUMBER));
allCopy.set(i, last);
break;
}
}
}
}
This works when it wants to and to be honest, it's probably really ugly. I just can't get my head around a better option.
The important method inside TicketItem is this one:
public boolean canBeGrouped(TicketItem other) {
if (other == null)
return false;
if (getBoolean(TicketItem.TICKET_ITEM_VOID))
return false;
if (other.getBoolean(TicketItem.TICKET_ITEM_VOID))
return false;
if (getInteger(TicketItem.MENU_ITEM) == null)
return false;
if (getInteger(TicketItem.MENU_ITEM).equals(other.getInteger(TicketItem.MENU_ITEM))
&& getBigDecimal(TicketItem.TICKET_ITEM_TOTAL).compareTo(
other.getBigDecimal(TicketItem.TICKET_ITEM_TOTAL)) == 0) {
ArrayList<TicketItemModifier> mThis = getModifiers();
ArrayList<TicketItemModifier> mOther = other.getModifiers();
if (mThis == null && mOther == null)
return true;
if (mThis != null && mOther != null) {
if (mThis.size() == mOther.size()) {
for (int i = 0; i < mThis.size(); i++) {
TicketItemModifier m1 = mThis.get(i);
TicketItemModifier m2 = mOther.get(i);
Integer m1MenuModifierId = m1.getInteger(TicketItemModifier.MENU_MODIFIER_ID);
Integer m2MenuModifierId = m2.getInteger(TicketItemModifier.MENU_MODIFIER_ID);
if (!(m1MenuModifierId != null && m2MenuModifierId != null && m1MenuModifierId
.equals(m2MenuModifierId))) {
return false;
}
}
return true;
}
}
}
return false;
}
Again, super ugly especially the for loop in there that works when it wants to. If need be I can modify hashCode and equals methods for both classes TicketItem and TicketItemModifier, however I would like to stay away from those two methods and do something along the lines of Comparable classes because just because they can be grouped does not mean they are equal.
What I want to do basically is go through one ArrayList filled with TicketItem objects and when two can be grouped I need to change the TicketItem object to match it.
I would suggest you create a new property or function like TickeItemCode which should be string concatenation of MENU_ITEM+ "-"+ TICKET_ITEM_TOTAL+ "-" + MENU_MODIFIER_IDs in modifiers list. you can filter the list to remove items where TICKET_ITEM_VOID is true and then sort by new property TickeItemCode and do grouping. This way you can reduce your time from n^2 to nlogn
I have a method that takes an array as a parameter and returns a boolean.
Inside the method, I have an if/else statement. If the statement is true, I want the result to return true, if the statement is false, I want the statement to returns false.
public static boolean allPositive (double[] arr)
{
for (int i = 0; i < arr.length; i++)
{
if(arr[i] > 0)
{
return true;
}
else
{
return false;
}
}
return //What do i put here?
}
}
Of course, it needs a return value at the end. However, I am confused on what I should return at the bottom. How should I rewrite this?
First, your code is wrong. For example, with {1, -1, 2}, your method will return true.
If you write it differently, you avoid the problem :
public static boolean allPositive (double[] arr) {
for (int i = 0; i < arr.length; i++) {
if(arr[i] < 0)
{
return false;
}
}
return true;
}
EDIT : Or even better, a one-line solution with Java 8 and Streams (I like one-line solutions):
public static boolean allPositive (double[] arr) {
//Stream the array and see if any elements matches condition `<0`.
return !Arrays.stream(arr).anyMatch(i->i<0);
}
If you need more than one line of code in order to work with collections, then you should learn about Streams.
public static boolean allPositive (double[] arr)
{
boolean b = true;
for (int i = 0; i < arr.length; i++)
{
if(!(arr[i] > 0))
{
b = false;
}
}
return b;
}
The way Java works, it ensures no problems with your code by making sure all your returns happen outside of the if else statement. This because, a common bug by programmers is to return in the if else statement, but never create an else condition, so the method never returns anything. Doing it this way is more of a good practice thing so you don't bug out later trying to figure out why a method won't return.
The answer by Arnaud has multiple return statements. Code smell. The answer by DreadHeadedDeveloper has a logic error if the array is {1,-1,2}, it returns true.
This function/method is terse and follows good coding practices.
public static boolean allPositive (double[] arr) {
boolean ret = true;
for (int i = 0; i < arr.length; i++) {
if(arr[i] <= 0) {
ret = false;
}
}
return ret;
}
You have to return in the end of the method (after the loop) the value that should be returned if an empty array is passed to your method. It's up to you to decide whether an empty array is "allPositive" or not.
Okay, so my question is regarding boolean returns. For my Comp Sci homework, I have to make a course registration program using methods, and one of them is an add course method. Basically, you search for the class in a catalog, and if it matches you add it to the students schedule and return a boolean value of true. I did this, but for some reason it is giving me an error. Here is the code:
public static boolean addCourse(
Course[] catalog,
Course[] mySchedule,
int myNumCourses,
int dept,
int courseNum)
{
int j;
int i;
int k;
int deptCat;
int courseNumCat;
Course courseAdd = null;
char checkDay;
int checkTime;
if (mySchedule.length == myNumCourses) {
return false;
}
for (i = 0 ; i < catalog.length ; i++) {
Course course = catalog[i];
deptCat = course.getDepartment();
courseNumCat = course.getCourseNumber();
if (deptCat == dept && courseNumCat == courseNum) {
courseAdd = catalog[i];
break;
}
else continue; }
for (j = 0 ; j < myNumCourses ; j++) {
if (mySchedule[j] == null) {
mySchedule[j] = courseAdd;
return true;
}
else continue;
}
for (k = 0 ; k < mySchedule.length ; k++) {
Course course = mySchedule[k];
if (course != null) {
checkDay = course.getDay();
checkTime = course.getPeriod();
if (checkDay == courseAdd.getDay() && checkTime == courseAdd.getPeriod()) {
return false;
}
}
else continue;
}
}
Why doesn't it recognize the boolean return values? Is it because I placed them inside a loop?
You need to place a return-statement at the end of your method, even if you might know it will never be reached (the compiler is not smart enough to know that, which explains the error).
For instance, even this will not compile:
public static boolean foo() {
if (true)
return true;
}
unless we add a final return statement. What you have is analogous.
There is nothing wrong with putting your return values in loops, however, the compiler sees no guarantee that this method will return a value and thus raises an error. At the very end of the method you need to return either true or false, whichever is most appropriate. All of your returns are within conditionals and therefor could fail to execute leaving your function with no return statement.
You must explicitly return a boolean(true/false) in ALL code path.Because your function's return type is "boolean".
In your case,you must add a return statement after the last loop.
If you don't want to write to many "return xx" statement,you can change the return type of this function to "void".And throw Exception in the false cases.
I think there is a problem with the last loop. If the condition for returning false is never met, it continues until it get to the end of the schedule, without returning anything. If you were to add a return at the end of the method this loop could fall through to it. Did you mean to return true after the loop, if no 'return false' is executed?
for (k = 0; k < mySchedule.length; k++) {
Course course = mySchedule[k];
if (course != null) {
checkDay = course.getDay();
checkTime = course.getPeriod();
if (checkDay == courseAdd.getDay()
&& checkTime == courseAdd.getPeriod()) {
return false;
}
} else
continue;
}
Where ever you are using if statement its possible else also must return or flow must go to another return.ELSE is missing with return.