A more efficient alternative to if statements - c#

I have a desktop C# app.
I have a nested loop.
I am comparing values between to multi arrays using the 'if' statement.
this is my code:
for (int x = 0; x < FRAME_HEIGHT; x++)
{
for (int y = 0; y < FRAME_WIDTH; y++)
{
if ((Shared.MotionState[camIndex].PreviousGrid[y, x] != Shared.MotionState[camIndex].DiffCurrentPrevious[y, x]
&& Shared.MotionState[camIndex].DiffCurrentPrevious[y, x] == 1))
{
diffGrids[camIndex][y, x] = 1;
diff++;
}
else
{
diffGrids[camIndex][y, x] = 0;
}
}
}
Now I know I could flatten the arrays but it will still need to use the if statements.
I am not saying there is anything wrong is this I am just asking whether this is the most memory efficient way of doing this.
N.B.
The diff grid is a static modular grid I have created at run-time.
Thanks

Related

How to display a simple hollow asterisk rectangle in console?

Could someone advise me on a simple way to implement hollow rectangles in C#?
I have been able to make a simple rectangle, but hollow rectangle programs I've looked at either contained or arrays or were pretty convoluted. For instance, the solution on another forum that seems too challenging, and this answer on CodeReview.SE is too difficult to understand.
This is what I've done, which displays a simple (filled) rectangle. How to output a hollow rectangle using if logic if possible?
class Nested_Loops_Hollow_Rectangles
{
public void RunExercise()
{
// how are now supposed to make this hollow?
// columns are side by side, rows is number of top to bottom
// see tut
Console.WriteLine("Welcome to the HollowRectanglePrinter Program.");
Console.WriteLine("How many columns wide should the rectangle be?"); //i.e. 4
int iColMax, iRowMax;
string userChoiceC = Console.ReadLine();
Int32.TryParse(userChoiceC, out iColMax);
Console.WriteLine("How many rows tall should the rectangle be? "); //i.e. 4
string userChoiceR = Console.ReadLine();
Int32.TryParse(userChoiceR, out iRowMax);
Console.WriteLine("Here you go:");
if (iRowMax > 0 || iColMax > 0)
{
for (int iRow = 0; iRow < iRowMax; iRow++)
{
for (int iCol = 0; iCol < iColMax; iCol++)
{
Console.Write("*");
}
Console.WriteLine();
}
}
}
}
The essential part of your application can be reduced to:
private void DrawFillRectangle(int width, int height)
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
Console.Write("*");
}
Console.WriteLine();
}
}
This, by the way (separating the logic and the input by putting the logic in a dedicated method) is what you should be doing. See Separation of concerns for more information.
The previous method draws a filled rectangle, so how can you draw a hollow one?
Start looking at the output. For instance, for (5, 3), the output is:
*****
*****
*****
and what you want is to have:
*****
* *
*****
How can you do that? Probably by replacing stars by spaces in some cases. Which ones?
Well, look again at the output. The first row is untouched, so the condition where you use spaces instead of stars is limited to rows other than the first one, that is:
private void DrawRectangle(int width, int height)
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (y > 0)
{
// Print either a star or a space.
}
else
{
Console.Write("*");
}
}
Console.WriteLine();
}
}
Now you must include the other cases in your condition: the first column, and the last column and row.
In order to combine conditions, you can use && and || operators. The first one means that the condition is true if both operands are true, and the second one means that either the first or the second operand is true.
It might be that your final condition will become too difficult to read. There are two things you can do. The first thing is to use intermediary variables. For instance:
if (a && b && c && d)
{
}
can be refactored into:
var e = a && b;
var f = c && d;
if (e && f)
{
}
if it makes sense to regroup a with b and c with d. A second thing you can do is to put the condition in a separate method, which may improve readability if you find a good name for the method:
private void DrawRectangle(int width, int height)
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (this.IsInsideRectangle(x, y))
{
// Print either a star or a space.
}
else
{
Console.Write("*");
}
}
Console.WriteLine();
}
}
private bool IsInsideRectangle(int x, int y)
{
return y > 0 && ...
}
This is hopefully all you need to do the exercise. Depending of your progression in the course, you may also be interested in those aspects:
You may avoid repeating code in an if/else block, so instead of:
if (...)
{
Console.Write(" ");
}
else
{
Console.Write("*");
}
you may end up writing only only Write():
Console.Write(...)
What C# operator can you use for that?
It is a good practice for a method to validate its input before doing its job. If you've already learnt what exceptions are, how can they be used to validate width and height? Why in the current situation it may make sense to not filter negative and zero values (in other words, would the application crash if, for instance, width is equal to -5)?
class emptyRectangle:Shape
{
byte width;
byte height;
public emptyRectangle(byte width,byte height)
{
this.width = width;
this.height = height;
}
public override void area()
{
Console.WriteLine("\n----------");
for (int i = 0; i < height; i++)
{
Console.WriteLine("");
for (int k = 0; k < width; k++)
{
if (i > 0 && k > 0)
{
if (i < height - 1 && k < width - 1)
{
Console.Write(" ");
}
else
Console.Write('*');
}
else
Console.Write("*");
}
}
}
}
Add a single IF statement where you are drawing the character:
if it is the first or last row or the first or last column, write the *
else the space.
For more fun, make a variable sized rectangular "hole" in the rectangle.
static void Main()
{
int width = 0, height = 0;
width = int.Parse(Console.ReadLine());
height = int.Parse(Console.ReadLine());
for (int i = 1; i <= height; i++)
{
for (int j = 1; j <= width; j++)
{
if ((i == 1 || i == height || j == 1 || j == width))
Console.Write("*");
else
Console.Write(" ");
}
Console.WriteLine();
}
Console.ReadKey();
}

move the values from a normal array to a 2D array - What's wrong with this code?

Basically I'm working on an assignment and I need to move the values from a normal array to a 2D array. I have to take input to set the length of the aray. The 2d array will be a square array, so say 3 is input my array needs to be 3x3. I've made the 1D array size n*n, with n being what the user inputs. I'm getting an index out of rage exception but I've gone through the code and written out what I think the values of everything should be at each stage and can't find out what's causing it.
public static void createTwoD(int[,] twoDArray, int[] startArray, int arrayLength)
{
for (int x = 0; x < arrayLength; x++)
for (int i = 0; i < arrayLength; i++)
twoDArray[i, x] = startArray[i * arrayLength + x];
}
The line getting the exception is the last line in that method. I'm passing in a 2D array of size [n,n], a 1D array of size [n*n] and the just n. If you want to see any more of the code let me know.
The problem is in you lines:
for (int x = 0; x < arrayLength; x++)
for (int i = 0; i < arrayLength; i++)
twoDArray[i, x] = startArray[i * arrayLength + x];
arrayLength variable makes jump out of bounds on startArray. Note that both x and i are in range from 0 to arrayLength
If you know already dimensions of your 2d array, you can easily achieve this by (here I assume it 3x3):
var x = 0;
for (int i = 0; i < arrayLength; i++) {
if(i!= 0 && i % 3 == 0) ++x; // go to another row
twoDArray[i, x] = startArray[i];
}
I would start by adding the following to the start of your method. These document your assumptions about the dimensions of the arrays passed as arguments.
Debug.Assert(twoDArray.Rank == 2);
Debug.Assert(startArray.Rank == 1);
Debug.Assert(twoDArray.GetLength(0) == arrayLength);
Debug.Assert(twoDArray.GetLength(1) == arrayLength);
Debug.Assert(startArray.GetLength(0) == arrayLength * arrayLength);
maybe twoDArray issnt initilized correctly:
public static void createTwoD(int[,] twoDArray, int[] startArray, int arrayLength)
{
//twoDArray musst be initialized correctly, otherwise use:
twoDArray = new int[arrayLength][arrayLength];
for (int x = 0; x < arrayLength; x++)
for (int i = 0; i < arrayLength; i++)
twoDArray[i, x] = startArray[i * arrayLength + x];
}

Two Dimensional List Loop

I am looping through a List<List<Shape>> object and checking if the horizontally and vertically adjacent objects are the same:
for (int x = 0; x < grid.Columns.Count; x++)
{
for (int y = 0; y < grid.Columns[x].Count; y++)
{
if (y != grid.Columns[x].Count - 1)
{
if (grid.Columns[x][y].Column == grid.Columns[x][y + 1].Column)
{
if (!shapesToDestroy.Contains(grid.Columns[x][y]))
{
shapesToDestroy.Add(grid.Columns[x][y]);
}
if (!shapesToDestroy.Contains(grid.Columns[x][y + 1]))
{
shapesToDestroy.Add(grid.Columns[x][y + 1]);
}
}
}
if (x != grid.Columns.Count - 1)
{
if (grid.Columns[x][y].Column == grid.Columns[x + 1][y].Column)
{
if (!shapesToDestroy.Contains(grid.Columns[x][y]))
{
shapesToDestroy.Add(grid.Columns[x][y]);
}
if (!shapesToDestroy.Contains(grid.Columns[x + 1][y]))
{
shapesToDestroy.Add(grid.Columns[x + 1][y]);
}
}
}
}
}
However, I always seem to get a ArgumentOutOfRange on
if (grid.Columns[x][y].Column == grid.Columns[x][y + 1].Column)
and
if (grid.Columns[x][y].Column == grid.Columns[x + 1][y].Column)
Before indexing these, I am performing a check as you can see to make sure that I do not get a ArgumentOutOfRange, but here I am. When I look at the index which is being + 1, it appears to be well under the size of the collection.
Can anyone see the obvious mistake and where I am going horribly wrong?
UPDATE
I updated the code by changing the checks for X and Y to:
if (x < grid.Columns.Count - 1)
and
if (y < grid.Columns[x].Count - 1)
I still get the same error.
FYI - The size of the collection is always the same. The size is: X = 5 and Y = 10
if (x != grid.Columns.Count - 1)
should be
if (x < grid.Columns.Count - 1)
since y is iterated from 0 to the maximum index of the list the operation
grid.Columns[x][y + 1]
will attempt to access an element with a higher index than what is currently in the list. If you want to keep the code above you should change the loop to only iterate to
for (int x = 0; x < grid.Columns.Count-1; x++)
{
for (int y = 0; y < grid.Columns[x].Count-1; y++)
{
}
}
I tried running your code, and i think you could get the functionality that you are looking for stripping it down to:
for (int x = 0; x < grid.Count; x++)
{
for (int y = 0; y < grid[x].Count; y++)
{
if (grid[x].Count > y && grid[x][y] == grid[x][y + 1])
{
if (!shapesToDestroy.Contains(grid[x][y]))
{
shapesToDestroy.Add(grid[x][y]);
}
if (!shapesToDestroy.Contains(grid[x][y + 1]))
{
shapesToDestroy.Add(grid[x][y + 1]);
}
}
if (grid.Count > x && grid[x+1].Count > y && grid[x][y] == grid[x + 1][y])
{
if (!shapesToDestroy.Contains(grid[x][y]))
{
shapesToDestroy.Add(grid[x][y]);
}
if (!shapesToDestroy.Contains(grid[x + 1][y]))
{
shapesToDestroy.Add(grid[x + 1][y]);
}
}
}
}
EDIT
Could also remove the second if in both of the cases since you have already tested that they are equal, doesn't really matter though since it won't change the result. Would just improve performance a tiny bit
it seems that your if condition does not seems correct
Try this
if (y < grid.Columns[x].Count - 1)
instead of
if (y != grid.Columns[x].Count - 1)
Probably your arrays are jagged. And the individual subarrays do not have the same length.
That could be a reason for getting an ArgumentOutOfRange-Exception in:
if (grid.Columns[x][y].Column == grid.Columns[x + 1][y].Column)
Why not use a foreach loop? then you won't have problems with the array out of bounds? Unless you are going for speed. You can use and then nest them as above.
foreach (int key in values.Keys)
{
Console.WriteLine("{0} is assigned to key: {1}", values[key], key);
}

How to Save a Multidimensional Array Index?

Basically my first task was to save the position of the '0' in an integer. Real simple with a standard array. This code loops through an array (Size: 8) until it locates the 0, then save that as the position. See code below:
p.s: n is a reference to an array saved somewhere else.
int position = 0;
this.nodesExpanded++;
// Loop through the array to get the position of where '0' is
for (int i = 0; i < n.getPuzzle().length; i++){
if (n.getPuzzle()[i] == 0){
position = i;
break;
}
}
My ultimate task was to make this possible for a multidimensional array (Size: [3, 3]). So here's what I've created thus far:
for (int x = 0; x < 3; x++)
{
for (int y = 0; y < 3; y++)
{
if (n.getPuzzle()[x,y] == 0)
{
**position = ;**
break;
}
}//end y loop
}//end x loop
So how do I go about saving an array reference to a location to a value?
'position' will need to be something other than int I'm guessing..
If you need more clarification be sure to comment, sorry in advance & thank you!
You can use a Tuple to store that position. Or you can create your own data structure.
Example: at the end you can see how to access tuple items.
var positions = new List<Tuple<int, int>>();
for (int x = 0; x < 3; x++)
{
for (int y = 0; y < 3; y++)
{
if (n.getPuzzle()[x,y] == 0)
{
positions.Add(new Tuple<int, int>(x,y));
break;
}
}//end y loop
}//end x loop
if(positions.Any())
{
var xpos = positions[0].Item1;
var ypos = positions[0].Item2;
}
I find a natural way to store a multidimensional array index is to use a single dimensional array whose size is the number of dimensions.
So if you have a object[,,] A and index int[] i you would index into A with the expression A[i[0],i[1],i[2]].
It works the same way as your one-dimensional array, but you have two position values to keep. I've used ints for the example, but you may want to use a custom structure or Tuple (as AD.Net) said.
int xpos = -1;
int ypos = -1;
for (int x = 0; x < 3; x++)
{
for (int y = 0; y < 3; y++)
{
if (n.getPuzzle()[x,y] == 0)
{
xpos = x;
ypos = y;
break;
}
}//end y loop
}//end x loop
if (!(xpos > -1 && ypos > -1)) ; // 0 was not found

Problem with output of mergesort algorithm

this code gives output but it has one problem that is when user write 5,6 in textbox1 and 7,8 in textbox3 it output 5,6.i know the problem is that when the elements of an array ends,it doesnt print the rest elements of other array,i commented on line of problem.
edited:i used textbox1 and textbox3 for getting the elements of the arrays that user wants to merge
private void button3_Click(object sender, EventArgs e)
{
string[] source = textBox1.Text.Split(',');
string[] source1 = textBox3.Text.Split(',');
int[] nums2 = new int[8];
int[] nums = new int[source.Length];
for (int i = 0; i < source.Length; i++)
{
nums[i] = Convert.ToInt32(source[i]);
}
int[] nums1 = new int[source1.Length];
for (int j = 0; j < source1.Length; j++)
{
nums1[j] = Convert.ToInt32(source1[j]);
}
int x = 0;
int y = 0;
int z = 0;
while (x < nums.Length && y < nums1.Length)
{
if (nums[x] < nums1[y])
{
nums2[z] = nums[x];
x++;
}
else
{
nums2[z] = nums1[y];
y++;
}
z++;
}////----->>it works untill here
while (x > nums.Length)///this mean when the elements of nums end,out the rest of the elements in other textbox but it doesnt do anything,whats the problem ?
{
if (y <= nums1.Length)
{
nums2[z] = nums1[y];
z++;
y++;
}
}
while (y > nums1.Length)
{
if (x <= nums.Length)
{
nums2[z] = nums[x];
z++;
x++;
}
}
string merge = "";
foreach (var n in nums2)
merge += n.ToString() + ",";
textBox4.Text = merge;
}
Do (remove your last while)
while (x < nums.Length)
{
nums2[z] = nums[x];
z++;
x++;
}
while (y < nums1.Length)
{
nums2[z] = nums1[y];
z++;
y++;
}
because you are not aware which array items remained, also your current code doesn't work anyway, because y is not related to nums and vise verse.
Edit: I copy past first while into second while, fix it, remove your last while loops (2 while with if in them) and replace this.
Both your conditions on while (x > nums.Length) and while (y > nums1.Length) don't make sense, since this will never happen.
In the block before, you increment x and y as long as they are smaller than nums.Length or nums1.Length. Therefore those will never become larger (at most equal), thus both conditions will always be false and the "remaining" items will not be merged in.
Note that there are other things wrong in your mergesort implementation, but that's not in the scope of your specific question I guess.

Categories