Detecting Circular Dependencies - java

Given a dependency tree of "Scenarios", I'm calculating the "weight" of each scenario branch.
I need to detect circular dependencies (scenario1 -> scenario2 -> scenario3 -> scenario1).
I'm currently doing a breadth-first search and passing a list down the recursion chain, however I'm not able to detect a circular dependency.
Each iteration I add the current scenario (String) to the List and then check dependsOnScenarios (an array of scenario names).
I should be just checking if a string is contained within a list of Strings but this scenario never catches it.
Am I adding to/checking the List at the wrong time?
Edit:
allScenarios is: a ConcurrentHashMap<String, Scenario>
dependsOnScenarios is a String[] and a property of Scenario
name is a String and a property of Scenario
getWeight is initially called with an empty list:
s.priority = getWeight(s, new ArrayList<String>())+1;
Input:
Scenario g1=new Scenario("Scenario1" , null);
Scenario g2=new Scenario("Scenario2" , new String[]{"Scenario4"});
Scenario g3=new Scenario("Scenario3" , new String[]{"Scenario1","Scenario2"});
Scenario g4=new Scenario("Scenario4" , new String[]{"Scenario3"});
Code:
private static int getWeight(Scenario scenario, List<String> visited) throws Exception{
int numDep = 0;
visited.add(scenario.name);
if(scenario.dependsOnScenarios != null){
for(String dependency:scenario.dependsOnScenarios) {
if(visited.contains(dependency)){
throw new Exception("Circular Reference: "+dependency+" has already occured");
}
return scenario.dependsOnScenarios.length + getWeight(allScenarios.get(dependency),visited);
}
}
return numDep;
}

My problem was that I was returning from the loop before I could evaluate and check the entire list. I needed to be using an additional loop to check everything fully fist.
private static int getWeight(Scenario scenario, List<String> visited) throws Exception{
int numDep = 0;
visited.add(scenario.name);
if(scenario.dependsOnScenarios != null){
for(String dependency:scenario.dependsOnScenarios) {
if(visited.contains(dependency)){
throw new Exception("Circular Reference: "+String.join("->",visited)+"->"+dependency);
}
}
for(String dependency:scenario.dependsOnScenarios) {
return scenario.dependsOnScenarios.length + getWeight(allScenarios.get(dependency),visited);
}
}
return numDep;
}

Related

Why does the last 2 elements gets repeated in the following implementation of double-ended list?

This is the Main class with main method for generating a double-ended list, remove and display its elements.
public class Main {
Link first, last;
public static void main(String args[]) {
Main ob = new Main();
Link arr[] = {
new Link(1), new Link(2), new Link(3)
};
int len = 3;
for(int i=0;i<len;i++)
ob.insertFirst(arr[i]);
System.out.print("Data in the list: ");
while(ob.first!=null)
System.out.print(ob.removeAndReturn()+", ");
for(int i=0;i<len;i++)
ob.insertLast(arr[i]);
System.out.print("\nData in the list: ");
while(ob.first!=null)
System.out.print(ob.removeAndReturn()+", ");
}
void insertFirst(Link arg) {
if(isEmpty())
last = arg;
arg.next = first;
first = arg;
}
// This removeAndReturn() method returns the Object data the link is holding and removes that Link from the list
Object removeAndReturn() {
Object ret = null;
try {
ret = first.data;
if(first.next==null)
last = null;
first = first.next;
}catch(NullPointerException NPe) {
System.out.println("You are referring to a null.\nLinked List is empty.");
}
return ret;
}
void insertLast(Link arg) {
if(isEmpty())
first = arg;
else
last.next = arg;
last = arg;
}
boolean isEmpty() {
return first==null;
}
}
class Link {
Object data;
Link next;
Link(Object data) {
this.data = data;
}
}
When executing, it gives the following output:
Data in the list: 3, 2, 1,
Data in the list: 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, ... {truncated}
Here the last two elements gets repeated in the output. I tried nullifying both the Link variables first and last before calling ob.insertLast(arr[i]) but it gives the same output.
Update:
private keywords are removed from the complete method signature for methods in the Main class other than main(String args[]) method and rmF() method is changed to removeAndReturn().
The main problem in your code lies in the fact that you're using the exact same nodes (the ones within the arr) to fill your list with head and tail insertions.
In fact, once you perform your first head insertion, those nodes have been linked to each other like this:
(3) => (2) => (1) => null
So, when you're performing your second insertion, you have that node 1 points to node 2, node 2 points to node 3, and theoretically node 3 should point to null since it's supposed to be the last element. However, node 3's next field is still pointing to node 2 from the previous insertion. This creates a loop where node 2 and node 3 keep pointing at each other; thus yielding the infinite loop you're experiencing.
(1) => (2) => <= (3)
To fix your problem you could either reset the next field of your nodes before re-using them (poor solution) or work with the actual data you need to structure rather than the nodes. In fact, the user of your class shouldn't be bothered with the details of your implementation and should only care about the info to be stored/represented (in your case int numbers).
This is a possible solution to your problem:
public class Main {
Link first, last;
public static void main(String args[]) {
Main ob = new Main();
//Array of int not of links
int[] arr = {1, 2, 3};
int len = 3;
for (int i = 0; i < len; i++)
ob.insertFirst(arr[i]);
System.out.print("Data in the list: ");
while (ob.first != null)
System.out.print(ob.removeAndReturn() + ", ");
for (int i = 0; i < len; i++)
ob.insertLast(arr[i]);
System.out.print("\nData in the list: ");
while (ob.first != null)
System.out.print(ob.removeAndReturn() + ", ");
}
//------ CORRECTION ------
//The method should receive the info the user needs to store.
//It will then be up to you to represent it as a Link or whatever
//internal structure you're going to use tomorrow. Don't bind the
//user to your internal implementation.
//------------------------
void insertFirst(int arg) {
//Generating a new node (or link) based on the given info
Link l = new Link(arg);
if (isEmpty())
last = l;
l.next = first;
first = l;
}
// This removeAndReturn() method returns the Object data the link is holding and removes that Link from the list
Object removeAndReturn() {
Object ret = null;
try {
ret = first.data;
if (first.next == null)
last = null;
first = first.next;
} catch (NullPointerException NPe) {
System.out.println("You are referring to a null.\nLinked List is empty.");
}
return ret;
}
//-------- CORRECTION --------
//same explanation given above
//----------------------------
void insertLast(int arg) {
//Generating a new node (or link) based on the given info
Link l = new Link(arg);
if (isEmpty())
first = l;
else
last.next = l;
last = l;
}
boolean isEmpty() {
return first == null;
}
}
Lastly, Do not capture RuntimeException. These are unchecked exceptions, not checked. You should investigate on their origin rather than simply catching them. What you've written is a bad practice.
https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html
As #JayC667 has already said, you could improve some designing and naming of your class, methods and variables. There are some conventions, especially when talking about data structures. For example:
Your class is called Main but it describes a List, a name like MyList would have been better.
Your utility class, Link, could have been placed within MyList as a static nested class and probably named Node (it's a better fit).
Some of your methods' names were a bit too cryptic. Self-explanatory names will better help the users of your class.
Avoid accessing the internal state of another object from outside (list.first != null). Methods should be your way to go to interrogate an object's state.
Using generic types could have been a better implementation than just Object as generics provide: strict checks at compile time, avoid casting a more type safety, the ability to re-use the same code for different data types.
https://docs.oracle.com/javase/tutorial/java/generics/why.html
Here is a link to an implementation with the suggestions made above:
https://www.jdoodle.com/iembed/v0/s7C

Returning a different type than the parameter

This is hw and I am really stuck on how to get my code to return what I want it to return. I am trying to return a String value with a given index value. I thought all I had to do was return the string value at the given index but I am not getting the right answer.
public void add(String candidate){
if (candidate.equals(null)){
throw new RuntimeException();
}
String[] contenders = new String[candidates.length+1];
// copy the array manually because I'm restricted from ArrayLists
for (int i = 0; i < candidates.length; i++){
contenders[i] = this.candidates[i];
}
this.candidate = candidate;
contenders[contenders.length-1] = this.candidate;
this.candidates = new String [contenders.length];
After adding values to a newly constructed array the tester wants to get the string value at a given index
public String get(int index){
if (index < 0 || index > candidates.length) {
throw new RuntimeException("Your argument was not within bounds.");
}
for (int i = index; i < candidate.length(); i++){
candidate = candidates[index];
}
return candidate;
I have been working on it and I finally was able to have candidate stop pointing to null it is giving the wrong value for the given index so for example I want 'X' at candidate[3] but I am getting 'Y' because that is the last value that candidate keeps. I have tried just returning candidates[index] but then it tells me that the value at that index is null. As I have gone through the debugger it appears that my original array is not being copied over properly but I am not sure what I should try next. Thanks in advance.
This is my constructor:
public CandidateList(){
candidates = new String[0];
}
public CandidateList(String[] candidates){
this.candidates = new String[candidates.length];
CandidateList candidateList = new CandidateList();
There is a lot that can be improved in your code, let me add some comments
public void add(String candidate){
//if candidate is actually null you are calling null.equals
//which means this will always result in a NullPointerException
//you can remove this if if you want
if (candidate.equals(null)){
throw new RuntimeException();
}
...
//think about what you are doing here,
//you are setting this.candidates to a new empty array
//(is big contenders.length, but still empty)
this.candidates = new String [contenders.length];
Second part:
public String get(int index){
//you are missing an '=' in index >= candidates.length
if (index < 0 || index > candidates.length) {
throw new RuntimeException("Your argument was not within bounds.");
}
//this for loop is wrong, you are changing 'i' but never use it..
//just return candidates[index] like you said before.
//It was probably null because of the error above
for (int i = index; i < candidate.length(); i++){
candidate = candidates[index];
}
return candidate;
A note on the RuntimeException(RE): if you catch a NullPointerException (NPE) and throw a RE you are actually losing information (since NPE is a more specific error rather than RE). If you want to catch/throw put at least a significant message like "candidate cannot be null"
Let's now analyze the constructor:
public CandidateList(){
candidates = new String[0];
}
public CandidateList(String[] candidates){
// you are doing the same error as above here:
// when you do this you create an EMPTY list of size candidates.lenght
// correct code is this.candidates = candidates
this.candidates = new String[candidates.length];
// this is not necessary, constructors don't need to return anything,
//here you are just creating a new instance that will not be used anywhere
CandidateList candidateList = new CandidateList();
Constructors create objects, they don't return data. I suggest you to take a look at this question Does a Java constructor return the Object reference? and in general read a bit more about constructors

Print Tree components

I am new to java and I want to create a very simple "word completion " program. I will be reading in a dictionary file and recursively adding the words into a Node array (size 26). I believe I have managed to do this successfully but I am not sure how to go through and print the matches. For the sake of testing, I am simply inserting 2 words at the moment by calling the function. Once everything is working, I will add the method to read the file in and remove junk from the word.
For example: If the words "test" and "tester" are inside the tree and the user enters "tes", it should display "test" and "tester".
If somebody could please tell me how to go through and print the matches (if any), I would really appreciate it. Full code is below.
Thank you
What you implemented is called "trie". You might want to look at the existing implementations.
What you used to store child nodes is called a hash table and you might want to use a standard implementations and avoid implementing it yourself unless you have very-very specific reasons to do that. Your implementation has some limitations (character range, for example).
I think, your code has a bug in method has:
...
else if (letter[val].flag==true || word.length()==1) {
return true;
}
If that method is intended to return true if there are strings starting with word then it shouldn't check flag. If it must return true if there is an exact match only, it shouldn't check word.length().
And, finally, addressing your question: not the optimal, but the simplest solution would be to make a method, which takes a string and returns a node matching that string and a method that composes all the words from a node. Something like this (not tested):
class Tree {
...
public List<String> matches(CharSequence prefix) {
List<String> result = new ArrayList<>();
if(r != null) {
Node n = r._match(prefix, 0);
if(n != null) {
StringBuilder p = new StringBuilder();
p.append(prefix);
n._addWords(p, result);
}
}
return result;
}
}
class Node {
...
protected Node _match(CharSequence prefix, int index) {
assert index <= prefix.length();
if(index == prefix.length()) {
return this;
}
int val = prefix.charAt(index) - 'a';
assert val >= 0 && val < letter.length;
if (letter[val] != null) {
return letter[val].match(prefix, index+1);
}
return null;
}
protected void _addWords(StringBuilder prefix, List<String> result) {
if(this.flag) {
result.add(prefix.toString());
}
for(int i = 0; i<letter.length; i++) {
if(letter[i] != null) {
prefix.append((char)(i + 'a'));
letter[i]._addWords(prefix, result);
prefix.delete(prefix.length() - 1, prefix.length());
}
}
}
}
Maybe a longshot here, but why don't you try regexes here? As far as i understand you want to match words to a list of words:
List<String> getMatches(List<String> list, String regex) {
Pattern p = Pattern.compile(regex);
ArrayList<String> matches = new ArrayList<String>();
for (String s:list) {
if (p.matcher(s).matches()) {
matches.add(s);
}
}
return matches
}

ArrayList in Session object seems to lose contents

I'm having a problem with retrieving and casting ArrayList from session. I get the following error:
javax.servlet.ServletException: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
I stored the arrayList in the session:
List<UserApplication> userList = uaDAO.searchUser(eds);
if (!userList.isEmpty()) {
request.getSession().setAttribute("userList", userList);
action_forward = EDITSUCCESS;
and for casting the session object to ArrayList, did the following:
EditStudentForm edt = (EditStudentForm)form;
if ((session.getAttribute("userList")) instanceof List){
List <UserApplication> studtList = (ArrayList<UserApplication>)session.getAttribute("userList");
}
try {
uaDAO.editUser(edt,studtList);
action_forward = EDITSUCCESS;
}
I'm getting the error over here in the DAO class:
public void editUser(EditStudentForm edt,List studtList) throws Exception {
PreparedStatement pst = null;
StringBuilder sb = new StringBuilder();
int stCode =Integer.parseInt(studtList.get(1).toString()); GETTING ERROR HERE
if (edt.getTitle() != null && !edt.getTitle().equals(studtList.get(2).toString())) {
sb.append("title = '").append(edt.getTitle()).append("'");
}
.
.
You are explicitly asking for 2nd (studtList.get(1)) and 3rd (studtList.get(2)) item in the list but never really make sure this list is big enough. Moreover your code apparently doesn't even compile:
if ((session.getAttribute("userList")) instanceof List){
List <UserApplication> studtList = ///...
}
try {
uaDAO.editUser(edt,studtList);
studtList is unaccessible in try block, also parenthesis in if statement are unmatched.
Check your studtList value.
From the error it seems your studtList only contain one item and you're try to get the second item with this code :
int stCode =Integer.parseInt(studtList.get(1).toString());
Change your code like this :
public void editUser(EditStudentForm edt,List studtList) throws Exception {
PreparedStatement pst = null;
StringBuilder sb = new StringBuilder();
if(studtList.size() > 1)
int stCode =Integer.parseInt(studtList.get(1).toString()); GETTING ERROR HERE
if (studtList.size() > 2 && edt.getTitle() != null && !edt.getTitle().equals(studtList.get(2).toString())) {
sb.append("title = '").append(edt.getTitle()).append("'");
}
}
In studtList there are no two elements and size of list maybe 1 or 0 elements, you should check it before try to call studtList.get(1). In ArrayList indexing start from 0 and if you want get first element you should call studtList.get(0).
In this code:
EditStudentForm edt = (EditStudentForm)form;
if ((session.getAttribute("userList")) instanceof List){
List <UserApplication> studtList = (ArrayList<UserApplication>)session.getAttribute("userList");
}
try {
uaDAO.editUser(edt,studtList);
action_forward = EDITSUCCESS;
}
You create a new variable 'studtList' that is never used. It's scope is only the { } pair around that one line.
There has to be another variable by that same name, studtList, in the outer scope so the 'editUser()' call can work.
Additional Note
As the other folks have answered, it looks like you may be doing a .get(1) and expecting the first element of the array list. Maybe. Maybe not.

NoElementException but I print the element and get the expected result

What I am trying to do is save a Move objects into a Vector called topMoves. There will be many Move objects which is why I create the object within the loop.
The pastPriceMap stores prices for stocks at some past time (in this case one minute ago). The currPriceMap stores price for stocks some time within the last second.
I get the following exception:
Exception in thread "Timer-0" java.util.NoSuchElementException
This is the line that is causing the problem:
amove.setInitPrice(pastPriceMap.get(iter.next()));
The code snippet is below. When I do the System.out.println statements I get the expected output:
Iterator<String> iter = sortedTopCodes.iterator();
while(iter.hasNext()){
System.out.println(currPriceMap.get(iter.next()));
System.out.println(pastPriceMap.get(iter.next()));
Move amove = new Move();
amove.setSecCode(iter.next());
amove.setPrice(currPriceMap.get(iter.next()));
amove.setInitPrice(pastPriceMap.get(iter.next()));
topMoves.add(amove);
}
return topMoves;
The Move class looks like this:
private String secCode;
private double price;
private double initPrice;
public String getSecCode() {
return secCode;
}
public void setSecCode(String secCode) {
this.secCode = secCode;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getInitPrice() {
return initPrice;
}
public void setInitPrice(double lastPrice) {
this.initPrice = lastPrice;
}
Short answer:
For each call to hasNext() there should be only one call to next()
In your code you have 5 next() with only one hasNext()
Here, read this: http://java.sun.com/javase/6/docs/api/java/util/Iterator.html
EDIT
Longer answer:
Basically an iterator is used to ... well iterate the elements of "something" tipically a collection but it could be anything ( granted that anything returns an Iterator ).
Since you may not know how many elements does that "anything" have, there must be a way to stop iterating right? ( if it was an array, you can tell by the length property, but the iterator is used to "encapsulate" the data structure used in the implementation ) Anyway.
The iterator API defines these two methods
-hasNext(): boolean
-next(): Object ( or <E> since Java 1.5 )
So the typical idiom is this:
while( iterator.hasNext() ) { // reads: while the iterator has next element
Object o = iterator.next(); // give me that element
}
What happens if the iterator has only two items?
while( iterator.hasNext() ) { // the first time will return true, so the next line will be executed.
Object o = iterator.next(); // give me that item. ( 1st element )
Object b = iterator.next(); // oops dangerous by may work ... ( 2nd element )
Object c = iterator.next(); // eeeerhhh... disaster: NoSuchElementException is thrown.
}
This is what is happening to you. You did not verify if the iterator has another element, you just retrieve it. If the iterator happens to have some elements, it may work for a while but there will be a time ( as you just saw ) when it fails.
By the way, DO NOT even think in catching NoSuchElementException. That's a runtime exception and it indicates that something in your code logic should be fixed.
See this answer to know more about the exceptions.
Here is a version using the new for loops:
for ( String secCode : secCodeList ) {
System.out.println(currPriceMap.get(secCode));
System.out.println(pastPriceMap.get(secCode));
Move amove = new Move();
amove.setSecCode(secCode);
amove.setPrice(currPriceMap.get(secCode));
amove.setInitPrice(pastPriceMap.get(secCode));
topMoves.add(amove);
}
in the older fashion :
String secCode = null;
for ( Iterator<String> it = secCodeList.iterator(); it.hasNext() ) {
secCode = it.next();
System.out.println(currPriceMap.get(secCode));
System.out.println(pastPriceMap.get(secCode));
Move amove = new Move();
amove.setSecCode(secCode);
amove.setPrice(currPriceMap.get(secCode));
amove.setInitPrice(pastPriceMap.get(secCode));
topMoves.add(amove);
}
// while there are more lines
while(scanner.hasNextLine())
{
final String line;
final String[] words;
// get the next line
line = scanner.nextLine();
// break the line up into the words (\\s+ should break it up via whitespace)
words = line.split("\\s");
if(words.length != 5)
{
throw new WhateverExceptionMakesSense(line + " must contain 5 words");
}
System.out.println(currPriceMap.get(words[0]));
System.out.println(pastPriceMap.get(words[1]));
Move amove = new Move();
amove.setSecCode(words[2]);
amove.setPrice(currPriceMap.get(words[3]));
amove.setInitPrice(pastPriceMap.get(words[4]));
topMoves.add(amove);
}

Categories

Resources