Why is this printing out the numbers from highest to lowest? - c#

I'm currently taking a intermediate course on Udemy for C# and I'm trying to do one of the exercises. I've looked in the Q&A for students to see other peoples solutions, I've even copied and pasted other peoples solutions to see if theirs works and they do, I don't see any difference between mine and other peoples but for some reason my code prints out the numbers from highest to lowest and no where in the code should this happen. The idea of the exercise was to create a stack, we have 3 methods: Push(), Pop(), and Clear(). The push method adds objects to an ArrayList, the pop method removes the number from the top of the stack and returns the number. The clear method is self explanatory. Here's my code:
Stack Class:
public class Stack {
private ArrayList _arrayList = new ArrayList();
public void Push(object obj) {
if (obj is null) {
throw new InvalidOperationException();
}
else {
_arrayList.Add(obj);
}
}
public object Pop() {
if (_arrayList is null) {
throw new InvalidOperationException();
}
else {
var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
}
}
public void Clear() {
for (int i = 0; i < _arrayList.Count; i++) {
_arrayList.Remove(i);
}
}
}
Program Class:
class Program {
static void Main(string[] args) {
var stack = new Stack();
stack.Push(5);
stack.Push(1);
stack.Push(2);
stack.Push(4);
stack.Push(3);
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
}
}

var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
You aren't printing the values, you're printing the number of elements stored.
Try changing your values to be something other than the first few positive integers to catch this kind of mistake more easily.
PS: There's been no reason to use ArrayList for over a decade. The generic collection classes such as List<int> are better in every way -- faster, less wasted memory, type safety.

var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
top is assigned the value of the size of the list, and is never reassigned. Thus it looks like it prints highest to lowest because its just printing the size of the stack (which of course is 5, then 4, then 3, and so on). It only looks like you printed the contents of your list because you happened to push the same numbers. Some different test data would have made this bug more obvious.
I think what you actually wanted was
var top = _arrayList[_arrayList.Count -1];
Note that your code would fail miserably if there was a duplicate element in the list (due to removing based on the item value and not on the index). You also really shouldn't be using ArrayList at all; that's a .NET 1.0 class that's just an awful collection interface. Use a generic like List<T>.

You are returning
var top = _arrayList.Count;
Not the value in that position.
_arrayList(top-1);
You should be getting an index out of range error on that remove.
_arrayList.Remove(top);

Related

Index out of range using lists and for loop

I have this loop here, which for each question it is supposed to create, it generates and then formats a 'worded question' from an array of questions, such as; 'What is the sum of {0} + {1}?'. This loop then formats it, adds the worded question and the answer to an array.
// Use for loop to create the correct amount of questions
for (int i = 0; i < Data.Questions.numQuestions; i++)
{
Random rnd = new Random();
Data.Questions.Sum sum = new Data.Questions.Sum();
// Create part one and part two of the question using random numbers
// ex. 3 + 5
// 3 = partOne, 5 = partTwo
int partOne = rnd.Next(Data.Questions.Sum.min, Data.Questions.Sum.max);
int partTwo = rnd.Next(Data.Questions.Sum.min, Data.Questions.Sum.max);
// Randomly select one of the word questions
string fullQuestion = Data.Questions.Sum.wordedQuestions[rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length)];
// Format the string with the generated numbers
fullQuestion = string.Format(fullQuestion, partOne, partTwo);
// Set out-of-class variables to be displayed to the user
Data.Questions.Sum.questions[i] = fullQuestion;
Data.Questions.Sum.answers[i] = partOne + partTwo;
}
Both Data.Questions.Sum.questions and Data.Questions.Sum.answers are List<string>'s and List<int>'s.
However, when this loop is run, with i = 0, I am thrown;
System.ArgumentOutOfRangeException: 'Index was out of range. Must be
non-negative and less than the size of the collection. Parameter name:
index'
Does anyone know what I'm doing wrong? As far as I know lists are dynamic, and I've defined like this;
// Arrays containing all questions and answers
// used to display questions and check answers
public static List<string> questions = new List<string>();
public static List<int> answers = new List<int>();
Also, to clarify, I do not want to use .Add(), as I have a settings panel which when you hit apply, re-runs this loop so the questions are up to date to the current settings. I need the loop to override the previous values.
Edit:
When using arrays, the better option here, I get;
System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'
On assigning Data.Questions.Sum.answers[i], after assigning the array like so; public static int[] answers {};
If you can't .Add() in this lists - create a copy of this lists and .Add() there. Lists has special for that kind of thing: new List<T>(IEnumerable<T>)
If you need to dynamically scale the collection, but you also need to iterate over it multiple times, then you'll need to check whether it is large enough to either insert, or just update.
You can do this with an extension method such as this...
public static class ListExtentions
{
public static void AddOrUpdate<T>(this List<T> that, int index, T value)
{
if (that.Count > index)
{
that[index] = value;
}
else
{
that.Add(value);
}
}
}
...which can then be called like this...
list.AddOrUpdate(index, value);
...however you can make things easier for yourself if you know how many questions you are going to have to start with.
If the number of questions changes when your UI changes, then you will also have to deal with the issue have scaling down the collection to ensure old elements are removed, which is much simpler if you just re-instantiate the collections every time you need to regenerate the questions / answers.
This is likly to be cause of your problem,(I have asked for clarification in comments where you didn't reply).
Still putting this as an answer, as it is potential error spot and you need to fix this.
As you mentioned you are facing this exception on i=0. there are high chanced that this is every time case not any specific case.
If Data.Questions.Sum.questions is empty then, Data.Questions.Sum.questions[i] = fullQuestion; , will surely throw such exception. Same way for Data.Questions.Sum.answers too.
In such case, you must use .Add() to insert into list.
so your code should be,
if (Data.Questions.Sum.questions.Count > i)
Data.Questions.Sum.questions[i] = fullQuestion;
else
Data.Questions.Sum.questions.Add(fullQuestion);
But if they are not empty, it must not be the cause of this exception.
One more thing i have noticed in your code is Data.Questions.Sum.wordedQuestions.
Even if you have valid list (here Data.Questions.Sum.wordedQuestions) - as you have Length prop, it must be Array not list.
If it is empty, while doing this
string fullQuestion = Data.Questions.Sum.wordedQuestions[rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length)];
this line will surely throw
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
as you are trying to get 0th index's data from it.
So before fetching data from list or array, first you need to check if it does have data init, and also it does have that index which you are asking.
something like
string fullQuestion = string.Empty;
if (Data.Questions.Sum.wordedQuestions != null &&
Data.Questions.Sum.wordedQuestions.Length > 0)
{
//here the way you are creating random number,
// you are assured about index is present in array.
int indexForWordedQuestion = rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length);
fullQuestion = Data.Questions.Sum.wordedQuestions[indexForWordedQuestion];
}

Stackoverflow only with very large ArrayLists

I'm using a recursive version of the insertion sort algorithm to sort 5000 objects based upon a randomly generated integer property, but I've been getting a stackoverflow exception only at an ArrayList of this size while working fine for ArrayLists of other sizes.
I used Console.WriteLine to see what the "position" integer goes up to in one of my methods and it ends up at `4719 before skipping a line and giving a stackoverflow exception. How should I get around this?
I should also mention that when testing an iterative version of insertion sort in the same Visual Studio solution and using an ArrayList of the same size of objects I do not get a stackoverflow exception.
My code for the recursive insertion sort is below (AL is the ArrayList):
public void IS()
{
ISRM(0);
}
private void ISRM(int position)
{
if (position == AL.Count)
return;
Console.WriteLine(position);
int PositionNext = position + 1;
ISRMNext(position, PositionNext);
ISRM(position + 1);
}
private void ISRMNext(int position, int PositionNext)
{
if ((PositionNext == 0) || (PositionNext == AL.Count))
return;
Webpage EntryNext = (Webpage)AL[PositionNext];
Webpage EntryBefore = (Webpage)AL[PositionNext - 1];
if (EntryBefore.getVisitCount() < EntryNext.getVisitCount())
{
Webpage temp = EntryBefore;
AL[PositionNext - 1] = AL[PositionNext];
AL[PositionNext] = temp;
}
ISRMNext(position, PositionNext - 1);
}
Well, first of all, sorting through recursive call is a bad idea for several reasons.
As you've already found out, this easily leads to a stack overflow due to limited size of the stack.
It will have poor performance by definition since function call and accompanying allocation of local function context on the stack is much more expensive operation compared to something like while or for operators iterating through plain collection.
These are two reasons why #Zer0 probably suggested it, but there's more to it.
There's ready ArrayList.Sort() method waiting for you that takes custom comparator. All you need is to write said comparator for your custom objects according to whatever rules you want and call Sort(your_comparator). That's it. You do not need to re-invent the wheel implementing your own sorting method itself - unless implementing sorting method is the actual goal of your program... but I honestly doubt it.
So, It could be something like this (not tested!):
class MyComparer : IComparer
{
public int Compare(object x, object y)
{
var _x = ((Webpage) x).getVisitCount();
var _y = ((Webpage) y).getVisitCount();
if (_x < _y)
{
return -1;
}
if (_x > _y)
{
return 1;
}
return 0;
}
}
Usage:
var myAL = new ArrayList();
// ... filling up the myAL
myAL.Sort(new MyComparer());

Enumerating over lambdas does not bind the scope correctly?

consider the following C# program:
using System;
using System.Linq;
using System.Collections.Generic;
public class Test
{
static IEnumerable<Action> Get()
{
for (int i = 0; i < 2; i++)
{
int capture = i;
yield return () => Console.WriteLine(capture.ToString());
}
}
public static void Main(string[] args)
{
foreach (var a in Get()) a();
foreach (var a in Get().ToList()) a();
}
}
When executed under Mono compiler (e.g. Mono 2.10.2.0 - paste into here), it writes the following output:
0
1
1
1
This seems totally unlogical to me. When directly iterating the yield function, the scope of the for-loop is "correctly" (to my understanding) used. But when I store the result in a list first, the scope is always the last action?!
Can I assume that this is a bug in the Mono compiler, or did I hit a mysterious corner case of C#'s lambda and yield-stuff?
BTW: When using Visual Studio compiler (and either MS.NET or mono to execute), the result is the expected 0 1 0 1
I'll give you the reason why it was 0 1 1 1:
foreach (var a in Get()) a();
Here you go into Get and it starts iterating:
i = 0 => return Console.WriteLine(i);
The yield returns with the function and executes the function, printing 0 to the screen, then returns to the Get() method and continues.
i = 1 => return Console.WriteLine(i);
The yield returns with the function and executes the function, printing 1 to the screen, then returns to the Get() method and continues (only to find that it has to stop).
But now, you're not iterating over each item when it happens, you're building a list and then iterating over that list.
foreach (var a in Get().ToList()) a();
What you are doing isn't like above, Get().ToList() returns a List or Array (not sure wich one). So now this happens:
i = 0 => return Console.WriteLine(i);
And in you Main() function, you get the following in memory:
var i = 0;
var list = new List
{
Console.WriteLine(i)
}
You go back into the Get() function:
i = 1 => return Console.WriteLine(i);
Which returns to your Main()
var i = 1;
var list = new List
{
Console.WriteLine(i),
Console.WriteLine(i)
}
And then does
foreach (var a in list) a();
Which will print out 1 1
It seems like it was ignoring that you made sure you encapsulated the value before returning the function.
#Armaron - The .ToList() extension returns List of type T as ToArray() returns T[] as the naming convention implies, but I think you are on the right track with your response.
This sounds like an issuse with the compiler. I agree with Servy that it is probably a bug, however, have you tried the following?
public class Test
{
private static int capture = 0;
static IEnumerable<Action> Get()
{
for (int i = 0; i < 2; i++)
{
capture++;
yield return () => Console.WriteLine(capture.ToString());
}
}
}
Additionally you may want to try the static approach, perhaps this will perform a more accurate conversion as your function is static.
List<T> list = Enumerable.ToList(Get());
When calling ToList() it seems as though it is not performing a single iteration for each value but rather:
return new List<T>(Get());
The second for each in your code does not make sense to me in implementation as to why it would ever be necessary or beneficial unless you require additional actions to be added/removed to the List object. The first makes perfect sense since all you are doing is iterating through the object and performing the associated action. My understanding is that an integer within the scope of the static IEnumerbale object is being calculated during conversion by performing the entire iteration and the action is preserving the int as a static int due to scope. Also, keep in mind that IEnumerable is merely an interface that is implemented by List which implements IList, and may contain logic for the conversion built in.
That being said I am interested to see/hear your findings as this is an interesting post. I will definitely upvote the question. Please ask questions if anything I said needs clarification or if something is false say so, although I am confident in my usage of the yield keyword of IEnumerable but this is a unique issue.

Run multiply instances of the same method simultaneously in c# without data loss?

I really don't understand Tasks and Threads well.
I have a method inside three levels of nested for that I want to run multiple times in different threads/tasks, but the variables I pass to the method go crazy, let me explain with some code:
List<int> numbers=new List<int>();
for(int a=0;a<=70;a++)
{
for(int b=0;b<=6;b++)
{
for(int c=0;b<=10;c++)
{
Task.Factory.StartNew(()=>MyMethod(numbers,a,b,c));
}
}
}
private static bool MyMethod(List<int> nums,int a,int b,int c)
{
//Really a lot of stuff here
}
This is the nest, myMethod really does a lot of things, like calculating the factorial of some numbers, writing into different documents and matching responses with a list of combinations and calling other little methods, it has also some return value (booleans), but I don't care about them at the moment.
The problem is that no task reach an end, it's like everytime the nest call the method it refreshes itself, removing previous instances.
It also give an error, "try to divide for 0", with values OVER the ones delimited by FORs, for example a=71, b=7, c=11 and all variables empty(that's why divided by zero). I really don't know how to solve it.
The problem is, that you are using a variable that has been or will be modifed outside your closure/lambda. You should get a warning, saying "Access to modified closure".
You can fix it by putting your loop variables into locals first and use those:
namespace ConsoleApplication9
{
using System.Collections.Generic;
using System.Threading.Tasks;
class Program
{
static void Main()
{
var numbers = new List<int>();
for(int a=0;a<=70;a++)
{
for(int b=0;b<=6;b++)
{
for(int c=0;c<=10;c++)
{
var unmodifiedA = a;
var unmodifiedB = b;
var unmodifiedC = c;
Task.Factory.StartNew(() => MyMethod(numbers, unmodifiedA, unmodifiedB, unmodifiedC));
}
}
}
}
private static void MyMethod(List<int> nums, int a, int b, int c)
{
//Really a lot of stuffs here
}
}
}
Check your for statements. b and c are never incremented.
You then have a closure over the loop variables which is likely to be the cause of other problems.
Captured variable in a loop in C#
Why is it bad to use an iteration variable in a lambda expression

Can I retrieve the stored value x in a hashset given an object y where x.Equals(y)

[TestFixture]
class HashSetExample
{
[Test]
public void eg()
{
var comparer = new OddEvenBag();
var hs = new HashSet<int>(comparer);
hs.Add(1);
Assert.IsTrue(hs.Contains(3));
Assert.IsFalse(hs.Contains(0));
// THIS LINE HERE
var containedValue = hs.First(x => comparer.Equals(x, 3)); // i want something faster than this
Assert.AreEqual(1, containedValue);
}
public class OddEvenBag : IEqualityComparer<int>
{
public bool Equals(int x, int y)
{
return x % 2 == y % 2;
}
public int GetHashCode(int obj)
{
return obj % 2;
}
}
}
As well as checking if hs contains an odd number, I want to know what odd number if contains. Obviously I want a method that scales reasonably and does not simply iterate-and-search over the entire collection.
Another way to rephrase the question is, I want to replace the line below THIS LINE HERE with something efficient (say O(1), instead of O(n)).
Towards what end? I'm trying to intern a laaaaaaaarge number of immutable reference objects similar in size to a Point3D. Seems like using a HashSet<Foo> instead of a Dictionary<Foo,Foo> saves about 10% in memory. No, obviously this isn't a game changer but I figured it would not hurt to try it for a quick win. Apologies if this has offended anybody.
Edit: Link to similar/identical post provided by Balazs Tihanyi in comments, put here for emphasis.
The simple answer is no, you can't.
If you want to retrieve the object you will need to use a HashSet. There just isn't any suitable method in the API to do what you are asking for otherwise.
One optimization you could make though if you must use a Set for this is to first do a contains check and then only iterate over the Set if the contains returns true. Still you would almost certainly find that the extra overhead for a HashMap is tiny (since essentially it's just another object reference).

Categories