Is it possible to pass a variable into a for loop? - c#

Is it possible to initialize 'int number' and pass it a value from the user input? I'm wondering if there's a cleaner way to do this by initializing number outside of the for loop.
for (int number = Convert.ToInt16(Console.ReadLine()); number < 10; number++)
{
Console.WriteLine(number);
}
I would like to do something like this, where a variables is initialed outside the loop, then handed directly in. - However this doesn't seem to work.
int n;
for (n; n<10; n++)
{
Console.Writeline(n)
}
I understand that it can be assigned and passed into the loop, but is it possible to do this without having to?
int n = Convert.ToInt16(Console.ReadLine());
for (int i = n; i<10; i++)
Console.Writeline(i);
in other words, can I use int n, without having to change it to i?

It's very close to what you had, just leave off the first part.
int n = 0;
for (; n < 10; n++)
{
Console.WriteLine(n)
}
Yeah this works, just tried in jsfiddle (https://dotnetfiddle.net/ZkL4BP). Just make sure nis initialized to something prior to the loop just int n gives a variable not initialized error.
As others are pointing out it is definitely an odd pattern, typically you want your for loop counter to only live the duration of the loop, and do whatever manipulation to other variables within the block. But it is accepted by the compiler.

You can do that by simply omitting the first part of the for statement
int n = Convert.ToInt16(Console.ReadLine());
for (; n<10; n++)
Console.Writeline(n);
Parts of the for statement are statements themselves and may contain arbitrary stuff - including an empty statement.
That said, you need to keep in mind that your variable is changed inside the loop. It's not great from the aspect of readability, so I wouldn't recommend it.

Related

For Loop isnt being fully completed

I have a For Loop which handles taking cards from the master deck, and putting them in a random order into the players deck. The code is:
for(int a = 0; a < deckManager.DeckAllCardsPlayer.Count; a++){
int b = Random.Range(0, deckManager.DeckAllCardsPlayer.Count);
if(!PlayerDeck.Contains(deckManager.DeckAllCardsPlayer[b])){
PlayerDeck.Add(deckManager.DeckAllCardsPlayer[b]);
deckManager.DeckAllCardsPlayer.RemoveAt(b);
}
}
There are 16 cards in the master deck, but this for loop only does 8. Can someone figure out why? Originally, it was adding some cards multiple times, which is why I added the '!PlayerDeck.Contains' statement. I have no idea why it's only doing 8 of 16.
The issue is that deckManager.DeckAllCardsPlayer.Count is getting smaller at each iteration. Try this instead:
while (deckManager.DeckAllCardsPlayer.Count > 0) {
int b = Random.Range(0, deckManager.DeckAllCardsPlayer.Count);
PlayerDeck.Add(deckManager.DeckAllCardsPlayer[b]);
deckManager.DeckAllCardsPlayer.RemoveAt(b);
}
I removed the conditional, because it shouldn't be necessary. (Unless the starting deck has duplicates? If so, just put it back in.)
You start off with 16 cards, but remove one each time.
As a result, although a decrease by one each iteration, the value of deckManager.DeckAllCardsPlayer.Count goes down.
After 8 iterations, a is 7, but the size of DeckAllCardsPlayer has been reduced to 8. Hence the loop terminates on the next turn.
One way to work around would be to take the count up front and store in an integer:
int totalCards = deckManager.DeckAllCardsPlayer.Count;
for(int a = 0; a < totalCards; a++){
... etc.
Although there are many other ways, depending on the logic that you want to expose.
This question may be enlightening : Is the condition in a for loop evaluated each iteration?
The upperbound or limit of the loop is changing as you remove cards from deck.
To fix it with just 2 line code change,
Try this
int count = deckManager.DeckAllCardsPlayer.Count;
for(int a = 0; a < count; a++){
int b = Random.Range(0, deckManager.DeckAllCardsPlayer.Count);
if(!PlayerDeck.Contains(deckManager.DeckAllCardsPlayer[b])){
PlayerDeck.Add(deckManager.DeckAllCardsPlayer[b]);
deckManager.DeckAllCardsPlayer.RemoveAt(b);
}
}
Assuming PlayerDeck & deckManager.DeckAllCardsPlayer are both lists then just do this:
PlayerDeck.AddRange(deckManager.DeckAllCardsPlayer.OrderBy(x => Random.value));
deckManager.DeckAllCardsPlayer.Clear();
Then you don't have to worry about removing elements while you iterate (which you should never do).
int count = deckManager.DeckAllCardsPlayer.Count;
for(int a = 0; a < count; a++){
int b = Random.Range(0, deckManager.DeckAllCardsPlayer.Count);
if(!PlayerDeck.Contains(deckManager.DeckAllCardsPlayer[b])){
PlayerDeck.Add(deckManager.DeckAllCardsPlayer[b]);
deckManager.DeckAllCardsPlayer.RemoveAt(b);
}
}
You must use count variable. Because deckManager.DeckAllCardsPlayer.Count will be changed after run deckManager.DeckAllCardsPlayer.RemoveAt(b). I hope it will work for you.

Loop stops all code after one iteration

I have a loop which in theory should loop 40000 times but exits and doesn't continue with code after the loop, just after one iteration. I figured that I wasnt being a silly willy about the for-loops since it didn't continue after the loops at all, so that might be something with restrictions for Lists? Or mayby something about the VS-debugger that isn't working preperly? (probably not tho...)
Edit: Thanks for pointing out that the last layer was pointless. I edited the code, but the problem persists.
Edit2: To clarify, the code does not result in an exception, or breaks. It just stops without any notifications, and shows the form(since I do a windows forms application). Just... it just don't want to continue and skips the rest of the code.
for (int i = 0; i < hiddenLayerDepth - 1; i++)
{
Connectors.Add(new List<List<List<List<Connector>>>>());
for (int j = 0; j < playfieldSize; j++)
{
Connectors[i].Add(new List<List<List<Connector>>>());
for (int k = 0; k < playfieldSize; k++)
{
Connectors[i][j].Add(new List<List<Connector>>());
for (int l = 0; l < playfieldSize; l++)
{
Connectors[i][j][k][l].Add(new Connector());
}
}
}
}
hiddenLayerDepth is set to 5 when entering the loop, and playfieldSize is set to 10. It enters the innermost loop and executes the code inside, then it just stops without increasing m.
Missing
Connectors[i][j][k].Add(new List<List<Connector>>());
If you know the sizes you should just create and array up front
Well, I tried to add a 'Connector' where there were no list. The List that contained the lists that would countain the Connectors was not added.

While debugging, how can I start a foreach loop at an arbitrary position in the enumeration?

I am debugging my program. Can I set a start object for the foreach loop in the debug mode? For instance, I want the foreach loop to start from the 5th element of my collection.
No, you cant. Foreach loop uses IEnumerable<T> where T is the type of object. So unlike for loop you cannot set initial or start index for the iteration. So you will always start from the 0th location object.
Other option is to use linq as shown below.
//Add using System.Linq statement at top.
int[] numbers = new int[] { 1,2,3,4,5,6,7,8};
foreach(var num in numbers.Skip(5))
{
Console.WriteLine(num);
}
Considering you are talking about debugging I'm assuming what you want to do is to break from the 5th element on etc. If this is the case then you can use a break point specifying a hit count which will break on the nth hit and so on.
See MSDN here.
An easy way to set the start object is to overwrite the variable that you are enumerating in the loop.
To illustrate, consider the following foreach loop.
IEnumerable<int> numbers = Enumerable.Range(1, 100);
foreach (int n in numbers)
{
Console.WriteLine(n);
}
Set your breakpoint on the numbers statement in the loop initializer, or step to the loop but don't run the numbers statement.
Use the immediate window to override the value of numbers:
numbers = numbers.Skip(5); // or Enumerable.Skip(numbers, 5)
Continue debugging; loop runs from the sixth element.
If your loop uses an inline-computed enumeration as follows, then you're out of luck. Consider using a hit-count breakpoint instead.
foreach (int n in Enumerable.Range(1, 100)) // no way to change enumeration.
{
Console.WriteLine(n);
}
Note: once the numbers statement is run, the debugger will cache your enumeration so it may no longer be changed and affect the loop. You may observe this while stepping through the loop construct.
foreach does not necessarily operate on a collection which does even have a defined order. consider a Dictionary<T> or a ConcurrentBag<T>.
so, no, this is not possible in the general case, especially without code changes (which could change the problem you are trying to debug).
#Shaggy's answer is probably the easiest, but it's good to know that the old fashioned for loop is the fastest, and enables you to skip the 0 index.
for(int x = 4; x < numbers.Length; x++)
{
// Do anything with numbers[x]
}
Even though I would not recommend it (It's really bad code), you could make this loop behave different when debugging, as you asked:
#if DEBUG
for(int x = 4; x < numbers.Length; x++)
#else
for(int x = 0; x < numbers.Length; x++)
#endif
{
// Do anything with numbers[x]
}

Off By One errors and Mutation Testing

In the process of writing an "Off By One" mutation tester for my favourite mutation testing framework (NinjaTurtles), I wrote the following code to provide an opportunity to check the correctness of my implementation:
public int SumTo(int max)
{
int sum = 0;
for (var i = 1; i <= max; i++)
{
sum += i;
}
return sum;
}
now this seems simple enough, and it didn't strike me that there would be a problem trying to mutate all the literal integer constants in the IL. After all, there are only 3 (the 0, the 1, and the ++).
WRONG!
It became very obvious on the first run that it was never going to work in this particular instance. Why? Because changing the code to
public int SumTo(int max)
{
int sum = 0;
for (var i = 0; i <= max; i++)
{
sum += i;
}
return sum;
}
only adds 0 (zero) to the sum, and this obviously has no effect. Different story if it was the multiple set, but in this instance it was not.
Now there's a fairly easy algorithm for working out the sum of integers
sum = max * (max + 1) / 2;
which I could have fail the mutations easily, since adding or subtracting 1 from either of the constants there will result in an error. (given that max >= 0)
So, problem solved for this particular case. Although it did not do what I wanted for the test of the mutation, which was to check what would happen when I lost the ++ - effectively an infinite loop. But that's another problem.
So - My Question: Are there any trivial or non-trivial cases where a loop starting from 0 or 1 may result in a "mutation off by one" test failure that cannot be refactored (code under test or test) in a similar way? (examples please)
Note: Mutation tests fail when the test suite passes after a mutation has been applied.
Update: an example of something less trivial, but something that could still have the test refactored so that it failed would be the following
public int SumArray(int[] array)
{
int sum = 0;
for (var i = 0; i < array.Length; i++)
{
sum += array[i];
}
return sum;
}
Mutation testing against this code would fail when changing the var i=0 to var i=1 if the test input you gave it was new[] {0,1,2,3,4,5,6,7,8,9}. However change the test input to new[] {9,8,7,6,5,4,3,2,1,0}, and the mutation testing will fail. So a successful refactor proves the testing.
I think with this particular method, there are two choices. You either admit that it's not suitable for mutation testing because of this mathematical anomaly, or you try to write it in a way that makes it safe for mutation testing, either by refactoring to the form you give, or some other way (possibly recursive?).
Your question really boils down to this: is there a real life situation where we care about whether the element 0 is included in or excluded from the operation of a loop, and for which we cannot write a test around that specific aspect? My instinct is to say no.
Your trivial example may be an example of lack of what I referred to as test-drivenness in my blog, writing about NinjaTurtles. Meaning in the case that you have not refactored this method as far as you should.
One natural case of "mutation test failure" is an algorithm for matrix transposition. To make it more suitable for a single for-loop, add some constraints to this task: let the matrix be non-square and require transposition to be in-place. These constraints make one-dimensional array most suitable place to store the matrix and a for-loop (starting, usually, from index '1') may be used to process it. If you start it from index '0', nothing changes, because top-left element of the matrix always transposes to itself.
For an example of such code, see answer to other question (not in C#, sorry).
Here "mutation off by one" test fails, refactoring the test does not change it. I don't know if the code itself may be refactored to avoid this. In theory it may be possible, but should be too difficult.
The code snippet I referenced earlier is not a perfect example. It still may be refactored if the for loop is substituted by two nested loops (as if for rows and columns) and then these rows and columns are recalculated back to one-dimensional index. Still it gives an idea how to make some algorithm, which cannot be refactored (though not very meaningful).
Iterate through an array of positive integers in the order of increasing indexes, for each index compute its pair as i + i % a[i], and if it's not outside the bounds, swap these elements:
for (var i = 1; i < a.Length; i++)
{
var j = i + i % a[i];
if (j < a.Length)
Swap(a[i], a[j]);
}
Here again a[0] is "unmovable", refactoring the test does not change this, and refactoring the code itself is practically impossible.
One more "meaningful" example. Let's implement an implicit Binary Heap. It is usually placed to some array, starting from index '1' (this simplifies many Binary Heap computations, compared to starting from index '0'). Now implement a copy method for this heap. "Off-by-one" problem in this copy method is undetectable because index zero is unused and C# zero-initializes all arrays. This is similar to OP's array summation, but cannot be refactored.
Strictly speaking, you can refactor the whole class and start everything from '0'. But changing only 'copy' method or the test does not prevent "mutation off by one" test failure. Binary Heap class may be treated just as a motivation to copy an array with unused first element.
int[] dst = new int[src.Length];
for (var i = 1; i < src.Length; i++)
{
dst[i] = src[i];
}
Yes, there are many, assuming I have understood your question.
One similar to your case is:
public int MultiplyTo(int max)
{
int product = 1;
for (var i = 1; i <= max; i++)
{
product *= i;
}
return product;
}
Here, if it starts from 0, the result will be 0, but if it starts from 1 the result should be correct. (Although it won't tell the difference between 1 and 2!).
Not quite sure what you are looking for exactly, but it seems to me that if you change/mutate the initial value of sum from 0 to 1, you should fail the test:
public int SumTo(int max)
{
int sum = 1; // Now we are off-by-one from the beginning!
for (var i = 0; i <= max; i++)
{
sum += i;
}
return sum;
}
Update based on comments:
The loop will only not fail after mutation when the loop invariant is violated in the processing of index 0 (or in the absence of it). Most such special cases can be refactored out of the loop, but consider a summation of 1/x:
for (var i = 1; i <= max; i++) {
sum += 1/i;
}
This works fine, but if you mutate the initial bundary from 1 to 0, the test will fail as 1/0 is invalid operation.

Ways in .NET to get an array of int from 0 to n

I'm searching the way(s) to fill an array with numbers from 0 to a random. For example, from 0 to 12 or 1999, etc.
Of course, there is a for-loop:
var arr = int[n];
for(int i = 0; i < n; i++)
{
arr[i] = i;
}
And I can make this method been an extension for Array class. But is there some more interesting ways?
This already exists(returns IEnumerable, but that is easy enough to change if you need):
arr = Enumerable.Range(0, n);
The most interesting way in my mind produces not an array, but an IEnumerable<int> that enumerates the same number - it has the benefit of O(1) setup time since it defers the actual loop's execution:
public IEnumerable<int> GetNumbers(int max) {
for (int i = 0; i < max; i++)
yield return i;
}
This loop goes through all numbers from 0 to max-1, returning them one at a time - but it only goes through the loop when you actually need it.
You can also use this as GetNumbers(max).ToArray() to get a 'normal' array.
The best answer depends on why you need the array. The thing is, the value of any array element is equal to the index, so accessing any element is essentially a redundant operation. Why not use a class with an indexer, that just returnes the value of the index? It would be indistinguishable from a real array and would scale to any size, except it would take no memory and no time to set up. But I get the feeling it's not speed and compactness you are after. Maybe if you expand on the problem, then a better solution will be more obvious.

Categories