I do apology in advance if there are many variables in the following code sample that their "types" is not clear to you, it is a big library, I just can't put all of that in here, so think of it at high-level, and the name of the variables is kind of helpful too...
Problem: A "concept" can have many "relations". Each of those relations can also have many concepts, For example like a father and child, a father has many children, a child may itsself be a father and has more children ,etc...
So I want to pass the root father and get all the hierarchy and write it to a file ...
The high-level code I am using is this, THE PROBLEM IS THAT it Crashes by a Null exception when it gets the child that has no more children. So its object is null in this line:
oUCMRConceptReltn = moTargetConceptList.ConceptReltns.get_ItemByIndex(i, false);
So I thought well let's put a not null check around it, yeah fixes the crash BUT after it sees the first leafe, it doesn't go further and algorithm stops.
So Something is wrong with the way I am calling recursion, but can't figure it out.
private void MyLoadMethod(string sConceptCKI)
{
UCMRConceptLib.UCMRConceptLoadQual oUCMRConceptLoadQual = new UCMRConceptLib.UCMRConceptLoadQual();
//Fill out UCMRConceptLoadQual object to get new list of related concepts
moTargetConceptList.Load(oUCMRConceptLoadQual;
// WHEN IT IS ZERO, THERE ARE NO MORE CHILDREN.
int numberofKids = moTargetConceptList.ConceptReltns.Count();
if (numberofKids == 0)
return ;
for (int i = 1; i <= numberofKids; i++)
{
oUCMRConceptReltn = moTargetConceptList.ConceptReltns.get_ItemByIndex(i, false);
//Get the concept linked to the relation concept
if (oUCMRConceptReltn.SourceCKI == sConceptCKI)
{
oConcept = moTargetConceptList.ItemByKeyConceptCKI(oUCMRConceptReltn.TargetCKI, false);
}
else
{
oConcept = moTargetConceptList.ItemByKeyConceptCKI(oUCMRConceptReltn.SourceCKI, false);
}
//write its name to the file...now recursion: go and find its children.
builder.AppendLine("\t" + oConcept.PrimaryCTerm.SourceString);
MyLoadMethod(oConcept.ConceptCKI);
}
return ;
}
Just as a side note, the check for number of kids being 0 is redundant, because you're never going to enter the loop.
The algorithm looks okay for what you want to do. You don't need to return anything in this case because your algorithm uses a side effect (the appendLine) to give your output.
I don't know C#, but it looks to me as if you're using some variables that are not local to the function, like oUCMRConceptReltn and oConcept. If they're not local to the function, different recursive invocations can change those values in unexpected ways. Recursive functions should almost never write to a variable outside its own scope.
Most indexes in c style languages are 0 based. So don't loop through 1 to numberofKids, loop 0 to numberofKids-1.
for (int i = 0; i < numberofKids; i++)
Related
I had two nested foreach loops that need to run through a significant amount of data and calculation. Regular foreach loops took far too long (several hours).
So, I looked up ways to speed it up and found Parallel.ForEach. This is my first time dealing with parallelisation but the examples seem easy enough.
Below is my code currently, the problem with this is local variables (I think, at least). errors are added for nodes that work fine outside of the parallel loops.
Parallel.ForEach(allNodes, (startNode) =>
{
Parallel.ForEach(allNodes, (endNode) =>
{
if (startNode != endNode)
{
List<Geo_Model_Struct> route = pathfinder.getRouteOptimised(startNode, endNode);
if (route.Count <= 0)
{
//failed to find route
errors.Add(string.Format("Cound not find a route from {0} to {1}", startNode, endNode));
}
else
{
List<Geo_Model_Struct> accessibleRoute = accessiblePathfinder.getRouteOptimised(startNode, endNode);
if (accessibleRoute.Count <= 0)
{
//failed to find route
errors.Add(string.Format("Cound not find an accessible route from {0} to {1}", startNode, endNode));
}
}
}
endCount++;
System.Diagnostics.Debug.WriteLine("I: {0}/{1}\tJ: {2}/{3}", startCount, allNodes.Count - 1, endCount, allNodes.Count - 1);
}
);
startCount++;
});
I'm guessing it's something to do with the route local variable being altered when it shouldn't as nearly all checked routes fail. But I don't know how to reliably debug this kind of thing so any help is appreciated.
Edit:
I am testing all possible routes to make sure they all work. route.Count should be > 0 for most tests. When using traditional foreach loops this is the case (e.g. 15 out of 500 times route.Count <= 0 is true)
When using Parallel.ForEach route.Count is 0 most of the time (e.g. somewhere in the region of 494 out of 500 times) so very few actually pass the test and when looking at the errors produced most that fail in parallel, pass using the traditional foreach
Solved
I found a way to remove the need to get data from the database within the getRouteOptimised method. This fixed the issue. Still not sure exactly what it is about the db connection that caused the problem, but it works now.
Without seeing the rest of your code, I suspect the issue is with the pathfinder and accessiblepathfinder objects. They may not be thread safe. A possible way to circumvent this is to create those variables locally within the inner foreach loop.
if (startNode != endNode)
{
// Create and Initialise pathfinder here
MyPathFinderObject pathfinder = new MyPathFinderObject(<parameters>);
List<Geo_Model_Struct> route = pathfinder.getRouteOptimised(startNode, endNode);
if (route.Count <= 0)
.../...
else
{
// Create and Initialise accessiblePathfinder here
MyAccessiblePathFinderObject accessiblePathfinder = new MyAccessiblePathFinderObject(<parameters>);
List<Geo_Model_Struct> accessibleRoute = accessiblePathfinder.getRouteOptimised(startNode, endNode);
.../...
}
}
However there is no guarantee that this will work.
From the docs:
You must be extremely cautious when getting data from properties and methods. Large object models are known for sharing mutable state in unbelievably devious ways.
I have an array of textboxes in which they change dyanmically depending on what the user types in. Those textboxes contain a number which represents a score of an assignment. Those score are linked to a module object. So if the user has 3 modules; 2 assignments on the first and second module and 3 assignments on the third module; then in total there would be 7 textboxes created for the user to input all their assignment marks.
What I am trying to do is to create a keyup event handler in which it gets the number in typed in by the user, and then dynamically calls a method to display the average of the the module. This is what I have so far. The following method gets called whenever the user types in a character:
public void calculateLevel4Modules(int counter) {
//iterate through modules
//iterate through assignts in that module
//whilst iterating, check tb and set userscore
//after iterating, update overall label with regards to modulecounter
//int assignmentCounter = 0;
//Console.WriteLine("in If statement.. " + counter);
for (int moduleCounter = 0; moduleCounter < requiredLevelList().Count; moduleCounter++)
{
int totalNumberOfAssignmentsInCurrentModule = requiredLevelList().ElementAt(moduleCounter).Assignments.Count;
Console.WriteLine("total number of assignmetns: " + totalNumberOfAssignmentsInCurrentModule);
assignmentCounter = assignmentCounter + totalNumberOfAssignmentsInCurrentModule;
Console.WriteLine("assignment counter: " + totalNumberOfAssignmentsInCurrentModule);
if (counter < assignmentCounter)
{
Console.WriteLine("in If statement.. " + userMarksTBLvl4[moduleCounter].Text);
try
{
int userMark = int.Parse(userMarksTBLvl4[counter].Text);
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
double modAvg = requiredLevelList().ElementAt(moduleCounter).getModuleScoreOverall();
moduleOverallLvl4[moduleCounter].Text = modAvg.ToString();
break;
}
catch (FormatException) { break; }
}
else { }
}
it works fine if the user has one module but if the user has two or more, then I get an error in the following line:
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
I am getting an out of bounds exception. I know why; its because counter is basically the # of the textbox that was typed into but by me using counter, I am accessing something not within the assignments list. This is an example of when the problem occus:
The user has 2 modules. In each module there are 2 assignments thus 4 textboxes are been created with their index ranging from 0 - 3. If the user wants to type in their score of the first assignment on the second module, its basically trying to write to the third index in that element then it crashes since that module only consist of 2 assignments.
There are some strange things in your code that make it hard to answer. First, the code you posted doesn't compile, so we have no way to test it.
Several times you use code like:
requiredLevelList().ElementAt(moduleCounter)
I assume requiredLevelList is a method that returns a list of things. There is no reason to assume requiredLevelList returns the same list, or even lists with the same number of elements, each time you call it. Maybe it does in your particular case, but this is a dangerous thing to rely on. You should use a construct like:
foreach (var module in requiredLevelList())
{
int totalNumberOfAssignmentsInCurrentModule = module.Assignments.Count;
...
module.Assignments.ElementAt(counter).UsersScore = userMark;
...
}
Code like this:
Console.WriteLine("total number of assignmetns: " + totalNumberOfAssignmentsInCurrentModule);
is symptomatic of trying to debug something after it has crashed. That is extremely inefficient. Learn how to use a debugger; you will not become an effective programmer until you know how to do this.
requiredLevelList().ElementAt(moduleCounter).Assignments.ElementAt(counter).UsersScore = userMark;
You're probably getting an out-of-bounds exception here because counter is outside the indexes of Assignments. Since you never initialize or change counter, I have no way to know what it is or should be. A debugger will tell you this, use one.
the # of the textbox that was typed into but by me using counter, I am accessing something not within the assignments list.
OK, if you're typing something “not within the assignments list” then you have to test for that and decide what to do. Perhaps something like:
if (counter >= 0 && counter < module.Assignments.Count)
module.Assignments.ElementAt(counter).UsersScore = userMark;
else
throw new Exception("I really have no idea what you want to do here.");
This also looks wrong:
moduleOverallLvl4[moduleCounter].Text = modAvg.ToString();
You never tell us what moduleOverallLvl4 is, but here you're assuming it has the same size as what is returned by requiredLevelList(). Maybe they are in this particular case, but that is a dangerous assumption. If these values are related, moduleOverallLvl4 should be contained in whatever class implements requiredLevelList, and you should have a method that assigns getModuleScoreOverall() to the correct element of moduleOverallLvl4.
I have a method which should consider a collection of instances of a class and find the first positive number not present as an attribute in those instances.
Here is my situation: I have a class called GestorePersonale (an employee manager class) which administers a List of instances of Dipendente (an employee class). Each Dipendente has an ID which has to be unique among all of the other instances of Dipendente present in the List's.
When creating a new Dipendente I have to find an unique ID to assign to it.
For this task, I first find out the highest ID (Matricola) among all of the instances in the list and then cycle through all of the numbers from 0 to that ID to try to find a gap ID to use for the new Dipendente. If all else fails, I'll just assign an ID corresponding to max + 1.
Here is the method MatricolaMax() which is in charge of returning the highest ID between those of all of the instances in the List (I'm posting this code just for clarity, it is not the part the question focuses on, even though any suggestion for performance improvement would be highly appreciated here as well):
private uint MatricolaMax ()
{
// Looking for the highest ID
return dipendenti.OrderByDescending( dipendente => dipendente.Matricola ).First().Matricola;
}
and here is the method this question's title refers to:
private uint MatricolaLibera ()
{
var max = MatricolaMax();
for ( uint i = 0; i < max; i++ )
{
var conto = dipendenti.Where( dipendente => dipendente.Matricola == i ).Count();
if ( conto == 0 )
return i;
}
return max + 1;
}
As you can see in the code above, to find a gap ID I'm using a Where query to check whether a Dipendente instance with a Matricola (ID) corresponding to i exists.
If I were to do this using a for loop instead of the query, this would be the code I'd write:
private uint MatricolaLibera ()
{
var max = MatricolaMax();
bool found;
for ( uint i = 0; i < max; i++ )
{
found = false;
for( int j = 0; j < dipendenti.Count; j++)
if ( dipendenti[j].Matricola == i )
{
found = true;
break;
}
if ( !found )
return i;
}
return max + 1;
}
basically adding an inner for loop and a bool check to see if a free ID was found.
My question to you is the following:
Which of the two methods presented (query vs. inner for loop) performs the best? Does an even better solution exist?
Of course as Eric says, you should run the code to answer your question of which performs better. (But it should be run on sizes similar to what you will see in real use, not just small sizes.)
Some things I'll suggest:
Your MatricolaMax method is sorting the list to find the highest value. Sorting is at minimum O(n*logn), whereas simply enumerating the list and comparing the values would be O(n).
Both MatricolaLibra functions are going through the entire collection for each possible value. This is O(n*m). I would suggest going through the list once, putting each key in a dictionary, then enumerate the dictionary to find the first one that doesn't exist. This should be much faster.
Eric Lippert has the best answer to your main question, but to your "is there a better way question", here is an answer.
You can use an integer to hold the highest option found, as well as a bool array to hold used values. Assuming you have a good upper bound, you can do this with a single array, if you do not you will need to handle growing the array as needed. Then you can simply enumerate your list, marking used values and updating max if needed. If you have no idea an upper bound or it can be arbitrarily high, then use a different algorithm.
However at this point you are looking at some very non-trivial code (that can perform horribly if an upper bound is not known), so if your existing solutions work, use them.
Suppose I have the following code:
List<SomeObject> someObjects = ReturnListWithThousandsOfObjects();
foreach(SomeObject someobject in someObjects)
{
DoSomething.With(someObject);
}
And also suppose that after a minute of running I put a breakpoint on DoSomething.With(someObject);.
The debugger breaks for me just fine. But now I want to know what point am I at in my iteration of the list (assume the list is unordered/has no key).
Is there a way for the debugger to say "the foreach has run 532 of 2321 iterations"?
As a debugging one off isn't there an indexof method?
i.e.
quickwatch - someObjects.indexOf(someObject);
Added - Sorry if a bit brief.
As pointed out by Guffa this will work best if the values are unique or the default equality comparer EqualityComparer function uses a unique value (such as a custom GetHashCode/Equals overload).
public class ATest
{
public int number { get; set; }
public int boo { get; set; }
public ATest()
{
}
}
protected void Go()
{
List<ATest> list = new List<ATest>();
foreach(var i in Enumerable.Range(0,30)) {
foreach(var j in Enumerable.Range(0,100)) {
list.Add(new ATest() { number = i, boo = j });
}
}
var o =0; //only for proving concept.
foreach (ATest aTest in list)
{
DoSomthing(aTest);
//proof that this does work in this example.
o++;
System.Diagnostics.Debug.Assert(o == list.IndexOf(aTest));
}
}
This is for Visual Studio, but other IDEs should have something similar:
When you set a breakpoint you can right-click it and go to "Hit Count". You can setup some parameters there ("greater than or equal to " 0 will make it work like a regular breakpoint - so would "break always"). The interesting part is the Hit Count field (which can be reset).
This can solve the "number of iterations" part. For the total number I'm afraid you're going to have to find it yourself, assuming the collection you use has such a number readily available.
You can also set the breakpoint to fire after a very large number of hits, say a few thousands/millions (I don't know what is their limit).
Then, when the "real" breakpoint fires, the one where you want to know how many times the original breakpoint was hit, you can just examine it and reset it if needed.
Is this case, if you really wanted to know what the count is, wouldn't you use a for loop?
List<SomeObject> someObjects = ReturnListWithThousandsOfObjects();
for(int someObj= 1; someObj <= someObjects.Count; someObj++)
{
Console.WriteLine(string.Format("{0} of {1} iterations", someObj, someObjects.Count));
DoSomething.With(someObject[someObj]);
}
There will be no real difference in performance between the foreach and the for loops - therefore the for loop will be a better alternative for the situation you want to achieve.
Unless you manually keep count in a variable you won't be able to easily determine this. As the loop is iterating across your collection it just uses the enumerator to grab the next element in the collection tell there are no more elements at which point it exits.
To manually keep a count you would just do:
int count = 0;
List<SomeObject> someObjects = ReturnListWithThousandsOfObjects();
foreach(SomeObject someobject in someObjects)
{
count++;
DoSomething.With(someObject);
}
Now at any point you can pause execution and see which iteration you are on
Create an extension method on List and List which accepts a Action fold, Action sideFold that let's you accumulate side effects like checking for the existence of a debugger and breaking on accumulated state.
Yes it can. Here's how [in VS 2017] :
Set a break point inside the foreach loop
Right click the break point and select 'Actions'
In the text box, enter the following: $FUNCTION {list.Items.IndexOf(item)} where 'list' is the name of your list and 'item' is the current item
Continue running the code and watch the output window
I am having trouble implementing a sort algo (merge) for singly list as defined below
My mergesort method always gives me null..I am not able to figure out what is wrong
Can you guys help me out?
Node class
public class Node
{
private int data;
private Node next;
}
Linked List class
public class SSL
{
private Node head;
}
My merge sort code
public static void MergeSort(SSL a)
{
SSL x = new SSL();
SSL y = new SSL();
if (a.Head == null || a.Head.Next == null) // base case if list has 0 or 1 element
return;
AlternateSplitting(a, x, y);
MergeSort(x);
MergeSort(y);
a = SortedMerge(x, y);
}
I implemented following helper methods to implement merge sort
AlternateSplitting: This method will split the list into 2 lists
public static void AlternateSplitting(SSL src, SSL odd, SSL even)
{
while (src.Head != null)
{
MoveNode(odd, src);
if (src.Head != null)
MoveNode(even, src);
}
} // end of AlternateSplitting
This method will merge the 2 list and return a new list
public static SSL SortedMerge(SSL a, SSL b)
{
SSL c = new SSL();
if (a.Head == null)
return b;
else
if (b.Head == null)
return a;
else
{
bool flagA = false;
bool flagB = false;
Node currentA = new Node();
Node currentB = new Node();
while (!flagA && !flagB)
{
currentA = a.Head;
currentB = b.Head;
if (currentA.Data < currentB.Data)
{
MoveNodeToEnd(a, c);
currentA = a.Head;
if (currentA== null)
flagA = true;
}
else
if (currentA.Data > currentB.Data)
{
MoveNodeToEnd(b, c);
currentB = b.Head;
if (currentB== null)
flagB = true;
}
} // end of while
if (flagA)
{
while (currentB != null)
{
MoveNodeToEnd(b, c);
currentB = b.Head;
}
}
else
if(flagB)
{
while (currentA != null)
{
MoveNodeToEnd(a, c);
currentA = a.Head;
}
}
return c;
} // end of outer else
} // end of function sorted merge
I am not able to figure out what is
wrong Can you guys help me out?
Find a bug and you fix it for a day. Teach how to find bugs and believe me, it takes a lifetime to fix the bugs. :-)
Your fundamental problem is not that the algorithm is wrong -- though, since it gives incorect results, it certainly is wrong. But that's not the fundamental problem. The fundamental problem is that you don't know how to figure out where a program goes wrong. Fix that problem first! Learn how to debug programs.
Being able to spot the defect in a program is an acquired skill like any other -- you've got to learn the basics and then practice for hundreds of hours. So learn the basics.
Start by becoming familiar with the basic functions of your debugger. Make sure that you can step through programs, set breakpoints, examine local variables, and so on.
Then write yourself some debugging tools. They can be slow -- you're only going to use them when debugging. You don't want your debugging tools in the production version of your code.
The first debugging tool I would write is a method that takes a particular Node and produces a comma-separated list of the integers that are in the list starting from that node. So you'd say DumpNode(currentB) and what would come back is, say "{10,20,50,30}". Obviously doing the same for SSL is trivial if you can do it for nodes.
I would also write tools that do things like count nodes in a list, tell you whether a given list is already sorted, and so on.
Now you have something you can type into the watch window to more easily observe the changes to your data structures as they flow by. (There are ways to make the debugger do this rendering automatically, but we're discussing the basics here, so let's keep it simple.)
That will help you understand the flow of data through the program more easily. And that might be enough to find the problem. But maybe not. The best bugs are the ones that identify themselves to you, by waving a big red flag that says "there's a bug over here". The tool that turns hard-to-find bugs into self-identifying bugs is the debug assertion.
When you're writing your algorithm, think "what must be true?" at various points. For example, before AlternateSplitting runs, suppose the list has 10 items. When it is done running, the two resulting lists had better have 5 items each. If they don't, if they have 10 items each or 0 items each or one has 3 and the other has 7, clearly you have a bug somewhere in there. So start writing debug-only code:
public static void AlternateSplitting(SSL src, SSL odd, SSL even)
{
#if DEBUG
int srcCount = CountList(src);
#endif
while (src.Head != null) { blah blah blah }
#if DEBUG
int oddCount = CountList(odd);
int evenCount = CountList(even);
Debug.Assert(CountList(src) == 0);
Debug.Assert(oddCount + evenCount == srcCount);
Debug.Assert(oddCount == evenCount || oddCount == evenCount + 1);
#endif
}
Now AlternateSplitting will do work for you in the debug build to detect bugs in itself. If your bug is because the split is not working out correctly, you'll know immediately when you run it.
Do the same thing to the list merging algorithm -- figure out every point where "I know that X must be true at this point", and then write a Debug.Assert(X) at that point. Then run your test cases. If you have a bug, then the program will tell you and the debugger will take you right to it.
Good luck!