This is a subset of the problem I am trying to tackle. Assume that I have parsed some code and now I am trying to check if it is logically correct. One of those checks is that functions calls can't call themselves or be involved in another function calling each other or a function of a function calling each other, and so on.
I have tackled the problem and was able to easily solve the call to itself and one level down though it might not be the optimal code. Right now, performance is not an issue.
Here is the logic I have coded along with an example:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LoopTest {
public static void main(String[] args) {
List<Loop> test = new ArrayList<Loop>();
test.add(new Loop("Function1",new String[]{"Function2", "Function1"}));
test.add(new Loop("Function2",new String[]{"Function3", "Function1"}));
test.add(new Loop("Function3",new String[]{"Function1"}));
checkLooping(test);
}
public static void checkLooping(List<Loop> input) {
for(Loop main : input) {
for(int i = 0; i < main.getInputSize(); i++) {
if(main.getName().equals(main.getInputValue(i))) {
System.err.println("Looping condition found at " + main.getName());
}
for(Loop inside : input) {
for(int j = 0; j < inside.getInputSize(); j++) {
if(main.getInputValue(i).contains(inside.getName()) &&
main.getName().equals(inside.getInputValue(j))) {
System.err.println("Looping condition found between "
+ main.getName() + " and " + inside.getName());
}
}
}
}
}
}
}
class Loop {
private String name;
private String input[];
public Loop(String name, String input[]) {
this.name = name;
this.input = input;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String[] getInput() {
return input;
}
public void setInput(String[] input) {
this.input = input;
}
public int getInputSize() {
return input.length;
}
public String getInputValue(int i) {
return input[i];
}
public boolean contains(String search) {
if(name.contains(search))
return true;
else
return false;
}
#Override
public String toString() {
return String.format("%s %s", this.name, Arrays.toString(input));
}
}
This won't catch that Function1 exists in Function3. So if it is deeper than level 1, it won't catch it based on my logic. Is there another way to do so?
Thanks in advance!
Is there another way to do so?
Yes it is a graph traversal problem; specifically the problem of detecting circular references in (in this case) the graph of method calls.
A simple algorithm goes like this:
def detect_cycle(node, seen={}):
if seen contains node:
// found a cycle
seen.add(node)
foreach child in node.children:
detect_cycle(child, seen)
(You don't need an explicit graph structure to do this traversal. The same approach can be used to traverse/check a graph that is implied by another data structure.)
However, what we are actually doing here is checking for recursive calls. We won't be able to distinguish between recursion that terminates (which is ok) and infinite recursion (which is bad). And THAT is a really difficult problem. (In fact, computation theory says that the most general form of the problem of proving termination has no solution.)
As a matter or interest ( :-) ) the graph traversal algorithm above is an example of a program with good recursion. However, it would be a huge amount of work to write a program that can prove that it will terminate ... and identify the theoretical case where it won't!
Thanks to #StephenC
Here is my running code after I converted to using Map:
private static Map<String, List<String>> main;
// more code from above
public void detectCycle(String node, Stack<String> seen) {
if(seen.contains(node)) {
System.out.println("found cycle at " + node + " and " + seen.get(seen.size()-1));
return;
}
else
seen.push(node);
if(main.get(node) != null && main.get(node).size() != 0) {
for(int i = 0; i < main.get(node).size(); i++) {
detectCycle(main.get(node).get(i), seen);
}
}
if(!seen.isEmpty())
seen.pop();
return;
}
Related
In my java class, we are using junit test to test our methods. This section introduced using an interface.
this specific method I am having problems on is supposed to search an array at each index, looking for a matching string as the input.
In the junit test I have
void test()
{
MyClassList labTest = new MyClassList("CIS 120", "Fall", "Professor Awesome");
MyStudent george = new MyStudent("George","Lucas", "555-555-5555","george.lucas#starwars.com");
MyStudent gene = new MyStudent("Gene", "Roddenberry","666-666-6666", "gene.roddenberry#startrek.com");
MyStudent jordan = new MyStudent("Jordan" ,"Robberts", "755-555-5555", "jordan.robberts#wheeloftime.com");
labTest.insert(george);
labTest.insert(gene);
labTest.insert(jordan);
System.out.println(labTest.toString());
System.out.println(labTest.contains(george));
System.out.println(labTest.search("George"));
This is the code U have for the method search:
Note
protected MyStudent [] log;
protected int lastIndex = -1;
are global variables
package Lab2;
import java.util.Arrays;
import java.util.Scanner;
import Lab2.ClassListInterFace;
public class MyClassList implements ClassListInterFace {
protected String course;
protected String semester;
protected String teacherLastName;
protected MyStudent[] log;
protected int lastIndex = -1;
public MyClassList(String currCourse, String currSemester, String lastName, int maxSize) {
log = new MyStudent[maxSize];
this.course = currCourse;
this.semester = currSemester;
this.teacherLastName = lastName;
}
public MyClassList( String currCourse, String currSemester, String lastName)
{
log = new MyStudent[100];
this.course = currCourse;
this.semester = currSemester;
this.teacherLastName = lastName;
}
public void insert(MyStudent element) {
lastIndex++;
log[lastIndex] = element;
}
public boolean isFull() {
if (lastIndex == (log.length - 1))
return true;
else
return false;
}
public int size() {
return (lastIndex + 1);
}
public void clear()
{
for (int i = 0; i <= lastIndex; i++)
log[i] = null;
lastIndex = -1;
}
public String getName() {
return teacherLastName;
}
public boolean contains(MyStudent element) {
boolean found = false;
for( int location = 0;location <= lastIndex; location++)
{
if (element.equals(log[location])) // if they match
found = true;
}
return found;
}
public String toString()
{
String message = "Course " + course + "\n Semester " + semester + "\n Proffessor " + teacherLastName + "\n";
for (int i = 0; i <= lastIndex; i++) {
message += log[i].toString();
}
return message;
}
public int search(String x)
{
int answer = 0;
for(int i = 0; i < log.length; i++)
{
if(x.equalsIgnoreCase(log[i]))
answer++;
}
return answer;
}
I got this based off some code that the teacher gave us for reference, and I tweaked it a little.
This looks like something that can be done much more elegantly with a for loop. In my experience, using a more concise control structure designed for things like this can lead to far fewer chances of errors. While I'm not sure what exact issue you are looking for help with, I do notice that if you do find a match, you skip the next element without checking to see if it is also a match.
int location = 0;
while (location <= lastIndex)
{
if (x.equalsIgnoreCase(log[location]))
{ // if they match
answer ++;
location ++; //<-- Here's where you increment twice upon finding a match!
}
location++; //To fix with the smallest number of changes, just put this in an else clause
}
This entire block can be reduced to approximately half the lines and half the variables by changing it up to be a for loop. See below:
for(int i = 0; i < log.length; i++) {
if(x.equalsIgnoreCase(log[i].firstName))
answer++;
}
This is much easier to read, and far less prone to errors. Trying to keep track of an excessive number of variables or dividing out common operations (such as incrementing where you are) is just asking for issues. This four-liner is functionally equivalent to your above code block (aside from the fact it doesn't skip the following entry when it finds a match), yet has far fewer opportunities for a programmer to make a mistake. Always, when you can get away with it, use the control flow structure designed for the task.
Basically I would like to know if there is a way to "disable" an attribute within a block after a certain point.
For example check the following scenario:
for(int i=0;i<10;i++){
for(int j=i+5;j<50;j++){
//from here until end of the block I want to make sure I don't use **i** anymore.
print(j*5+i); //I want this line to produce compiler error
}
}
Don't get me wrong I understand it is a bad programming, but I still can't help but to use i,j,k,h as attributes. and sometimes I make a mistake by misplacing the attributes in wrong places.
Call a method.
for (int i = 0; i < 10; i++) {
for (int j = i + 5; j < 50; j++) {
doSomething();
}
}
...
private void doSomething() {
// Woot, no i and no j!
}
Your code doesn't make sense to anybody. You need to divide it into functions with good names so that anyone can understand what your program is doing without comments around the code or getting mixed up with variables.
Here's an example for the code you have posted:
public void printNumberTimes5(int number) {
print(number*5);
}
But don't stop there, make it obvious what the loop is doing too:
public void printSomeNumbers(int someNumber) {
for(int j=someNumber+5;j<50;j++){
printNumberTimes5(j);
}
}
And again:
public void printSomeNumbers_repeat(int repeat) {
for(int i=0;i<repeat;i++){
printSomeNumbers(i);
}
}
I don't really know what you're doing but renaming the function to what you're supposed to be doing would make it clear.
Remember: each function should only have one job.
Finally, give i and j real names so that you understand what those numbers do and don't mix them up.
The best way to obtain this in java, is by using scope. Make sure that the variables are in different scopes and then you don't have access to it. A good guideline to follow is to split your logic in various small methods, this way you'll ensure the desired behavior.
My recommendations in order of preference:
Use meaningful variable-names. Maybe i isn't as good as e.g. row, ...
Use functions to group operations and also reduce the variables they can access. This can also lead to a point where repeating operations can easily be reused.
Use a custom counter-object like this one
/**
* Created for http://stackoverflow.com/q/25423743/1266906
*/
public class ObliviousLoops {
public static void main(String[] args) {
for(LockableCounter i = new LockableCounter(0); i.getValue() < 42; i.unlock().increment()) {
System.out.println("A-loop:" + i.getValue());
i.lock();
// No access, everything is fine
}
for(LockableCounter i = new LockableCounter(0); i.getValue() < 42; i.unlock().increment()) {
System.out.println("B-loop1:" + i.getValue());
i.lock();
// Next statement will throw an Exception
System.out.println("B-loop2:" + i.getValue());
}
}
static class LockableCounter {
private long value;
private boolean locked;
LockableCounter(long value) {
this.value = value;
}
public LockableCounter lock() {
this.locked = true;
return this;
}
public LockableCounter unlock() {
this.locked = false;
return this;
}
public long getValue() {
if(locked) {
throw new IllegalStateException("Accessing locked counter");
}
return value;
}
public void increment() {
if(locked) {
throw new IllegalStateException("Accessing locked counter");
}
value++;
}
#Override
public String toString() {
if(locked) {
throw new IllegalStateException("Accessing locked counter");
}
return String.valueOf(value);
}
}
}
the most obvious draw-backs of the last solution is a less fluent handling of the value, less ways to optimize the operations for the compiler, ... in practice you may even want to replace the LockableCounter by something different, once you are sure you calculations are written as desired to speed things up.
Use Java 8's lambda-function to build something behaving similar to for-loops where you can null-out the counter for the rest of the cycle (actually this is a variant of #2)
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* Created for http://stackoverflow.com/q/25423743/1266906
*/
public class LambdaLoops {
public static void main(String[] args) {
iterate(0, 42, (i) -> {
System.out.println("A-loop:" + (i + 0));
i = null;
});
iterate(0, (i) -> i < 42, (i) -> ++i, (i) -> {
System.out.println("B-loop:" + (i + 0));
i = null;
});
iterate(0, (i) -> i < 42, (i) -> {
System.out.println("C-loop1:" + (i + 0));
i = null;
// Next statement will not throw an Exception
System.out.println("C-loop2:" + i);
// Next statement will throw an Exception
System.out.println("C-loop3:" + (i + 0));
});
}
static void iterate(Integer initial, Integer limit, Consumer<? super Integer> function) {
for (Integer i = initial; i < limit; i++) {
function.accept(i);
}
}
static void iterate(Integer initial, Predicate<? super Integer> when, Consumer<? super Integer> function) {
for (Integer i = initial; when.test(i); i++) {
function.accept(i);
}
}
static <T> void iterate(T initial, Predicate<? super T> when, Function<? super T, ? extends T> increment, Consumer<? super T> function) {
for (T i = initial; when.test(i); i = increment.apply(i)) {
function.accept(i);
}
}
}
as in #3 this will most likely lead to decreased performance, but has the advantage, that your IDE might alert you, that i will always be null. This should however be easier to optimize be inlining than #3 as there is no additional boolean involved. If and when the JIT does inlining is however hard to guess.
Since so many of answers talk about why this is a bad idea, so I won't repeat it.
One solution that comes to my mind is to use an counter object. Whenever you want a particular counter to go out of scope, set that to null. If you use it after this point, a Null pointer access warning is shown (at least in eclipse. I suspect other IDEs should also have this feature. Not sure whether javac generates a warning).
public class DisappearingVariables {
public static class Counter {
int i = 0;
public Counter() {
}
public void inc() {
i++;
}
public int get() {
return i;
}
}
public static void main(String[] args) {
for(Counter i = new Counter(), oi = i; i.get() < 10; i = oi, i.inc()) {
System.out.println("i = " + i.get());
i = null;
i.inc(); // This line gets a warning
for(int j = 0; j < 10; j++) {
}
}
}
}
I am trying to avoid repeating masses of code and was wondering if there was a short cut for it? I want a literal shortcut, which just replaces the shortcut with text in compilation.
for example:
private int a = 0;
/*Shortcut sc = new Shortcut ( for(a = 0; a < 5; a++) ); */
if (truth = true)
sc.doTask(a);
else
sc.doTask((a+1);
I know it doesn't affect the efficiency of coding, but makes the task look a bit more organized.
It seems what you are trying to do is will leave your code unmaintainable and hard to read (Unless you were asking how to organize your code in functions).
It's not always about coding efficiency. You have to make sure that your code is not harder to maintain and understand by other developers.
If you want to avoid repetition of code put the repeated code in some well defined methods.
public class Test {
public static void main(String[] args) {
Test test = new Test();
// Now you can use the so called shortcut that is called a method everywhere you want.
int sum = test.getSum(1, 2, 3);
System.out.println("Sum is " + sum);
// Now again reuse the method instead of loads of code :)
sum = test.getSum(2, 4, 5);
System.out.println("New sum is " + sum);
}
public int getSum(int... numbers) {
int sum = 0;
for (int num : numbers) {
sum += num;
}
return sum;
}
}
BTW. Your if(truth=true) is assignment to variable called "truth" and will always evaluate to true. Your else will never be called.
Ill take a stab. To reduce boiler plate code you can use methods. Take this example
public class MyFooClass {
private int[] numbers;
public void doStuff1() {
// do something
for(int i=0;i<numbers.length;i++) {
// check for duplicates or something
}
}
public void doOtherStuff() {
// do something
for(int i=0;i<numbers.length;i++) {
// check for duplicates or something
}
}
}
as you can see we check for duplicates 2 times, we can reuse that code in another method.
public class MyFooClass {
private int[] numbers;
public void doStuff1() {
// do something
checkForDuplicatesOrSomething();
}
public void doOtherStuff() {
// do something
checkForDuplicatesOrSomething();
}
private void checkForDuplicatesOrSomething() {
for(int i=0;i<numbers.length;i++) {
// check for duplicates or something
}
}
}
Instead of calling System.out.println("blah blah blah my text"); each time you want to print something you could code your own method like this.
public void p(Object o) {
System.out.println(o);
}
Then in your code simply call this method like this:
String s = "foo";
StringBuilder sb1 = new StringBuilder("i hate this town");
p(s);
p(sb1);
I'm trying to evaluate the structure of a polynomial by simply listing the coefficients and displaying them with a variable with its respected power. I'm not evaluating, I'm just trying to get the equation out there.
public class TestPolynomialBackup{
public static void main(String[] args){
Polynomial p1 = new Polynomial(4);
System.out.println(p1);
}
public static class Polynomial
{
private int[] coef;
private int power=3;
public Polynomial(int a ){
coef = new int []{4,3,2,1};
}
public String toString() {
for(int i=0;i<coef.length-1;i++){
String s = coef[2] + "x^" + power;
return s;
}
}
}
}
Output: TestPolynomialBackup.java:38: error: missing return statement
}
I keep getting that error at the toString() method. All i'm trying to do is to make a for-loop that will go down the array of coefficents with some conditions that will determine if the character "x" (variable) will appear as well as the power.
You might wanna get more familiar with Java and think about what you want this method to do:
public String toString() {
for (int i = 0; i < coef.length - 1; i++) {
String s = coef[2] + "x^" + power;
return s;
}
}
This is propably what you want:
public String toString() {
StringBuilder s = new StringBuilder();
for (int i = 0; i < coef.length; i++) {
if (i != 0)
s.append(" + ");
s.append(coef[i]);
s.append("x^");
s.append(i);
}
return s.toString();
}
Changes:
put return outside of loop
accumulate result instead of somehow always creating a new string
actually use your index i inside of the loop
let the loop go from 0 to coef.length - 1
added " + " as a delimiter
You should add a return after your for loop.
The compiler can't compile because if your loop is not executed, your method would return nothing.
But you should review the way your loop is working, since you have a return in it, it is executed only once.
so I'm currently doing an exercise for college that has several optional parts (because we havn't done this in class yet), one of them being to use lists instead of arrays (so it'd be variable size) and another one printing the list sorted by points (I'll get to that now)
So, I have the Player.java class which looks like this.
public class Player {
String name;
String password;
int chips;
int points;
public Player(String n, String pw, int c, int p) {
name = n;
password = pw;
chips = c;
points = p;
}
public String getName() {
return name;
}
public void setName(String n) {
name = n;
}
public void setPW(String pw) {
password = pw;
}
public String getPW() {
return password;
}
public void setChips(int c) {
chips = c;
}
public int getChips() {
return chips;
}
public void setPoints(int p) {
points = p;
}
public int getPoints() {
return points;
}
}
Pretty simple, then I'm creating a List with this (in another class):
List<Player> lplayer = new ArrayList<Player>();
Adding players with this:
lplayer.add(new Player(n,pw,c,p))`
And finally reading their stats with this:
public int search_Player (String n) {
String name;
int i = 0;
boolean found = false;
while ((i <= tp) && (!found)) {
name = lplayer.get(i).getName();
if (name.equals(n)) {
found = true;
}
i++;
}
return (found == true) ? i-1 : -1;
}
public Player show_Player (int i) {
return lplayer.get(i);
}
public void list_Players() {
Collections.sort(lplayer);
int i2;
if (tp > 0) { // variable which contains number of total players
for (int i = 0;i<tp;i++) {
i2 = i+1;
System.out.println ("\n"+i2+". "+lplayer.get(i).getName()+" [CHIPS: "+lplayer.get(i).getChips()+" - POINTS: "+lplayer.get(i).getPoints()+"]");
}
}
else {
System.out.println ("There are no players yet.");
}
}
So that's basically all the code. As you can see the I already have a list_Players function but that just prints it in the order it was added. I need a way to print in sorted by the points each player has (so basically a ranking).
As you can see I'm pretty new to java so please try not to come up with a very complicated way of doing it.
I've already searched for it and found things like Collections.sort(list) but I guess that's not what I need right here.
Thank you!
You can use the public static <T> void sort(List<T> list, Comparator<? super T> c) overload in Collections - provide the comparator you need (can be just an anonymous class) - and you are all set!
EDIT:
This describes how the method works. In brief, you'll implement your call as
Collections.sort(list, new Comparator<Player>() {
int compare(Player left, Player right) {
return left.getPoints() - right.getPoints(); // The order depends on the direction of sorting.
}
});
That's it!
Collections.sort(list) could definitely by a solution for your problem. It's a way to sort your collections provided by Java. If you are writing a "real world" application (not an exercise for collage) this would be the way you doing it.
To let Collections.sort(list) works, you have to implement an interface call Comparaple. By implementing this interface, the sort will know how to order your elements.
But because it's a exercise for collage, this is perhaps a little bit to easy. If you want (or must) implement you own sorting algorithm, try first to sort a common list of numbers (1, 5, 2, 7...). You can extend such an sorting algorithm easily for your own classes.
A new approach using lambdas, that is a lot shorter to write is
myList.sort((obj1, obj2)->(condition)?1:-1);
where you can use the objects for your condition, and anything greater than 0 returned means swap (in this case if condition returns true)