Quick Search out of bounds of array and confusing array behaviour - c#

I'm having multiple problems with my program (C#.NET) and have no idea what's causing them.
The program is intended to sort a list of names and birthdays (formatted first name,last name,DD/MM/YYYY) in ascending and descending order by first name, last name, and birthday. It is also to have other functions which have not yet been implemented.
The first problem is in the quikSortStr method. The program crashes in the first if block, stating that j is out of the bounds of the array. This happens whether or not mode == "asc".
The second, and more confusing problem is that when the values are loaded from a text file, every odd-indexed value of first and last will be null, while each odd-indexed value of bDay will be 1/1/0001.
I've included the full program below for reference, a quicksort method and the use of parallel arrays are required. My apologies for the lack of comments.
Thanks in advance for any help. I'm completely stumped.
namespace Names_Arrays
{
public partial class frmNamArrays : Form
{
System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo("en-CA");
string[] first;
string[] last;
DateTime[] bDay;
string order = "asc";
string format = "d/M/yyyy";
public frmNamArrays()
{
InitializeComponent();
}
private void write()
{
string[] lines = new string[first.Length];
for (int i = 0; i < lines.Length; i++)
lines[i] = first[i] + ',' + last[i] + ',' + bDay[i].ToString(format);
txtbxNames.Clear();
txtbxNames.Lines = lines;
}
private void load()
{
string[] lines = txtbxNames.Lines;
first = new string[lines.Length];
last = new string[lines.Length];
bDay = new DateTime[lines.Length];
int i = 0;
foreach (string line in lines)
{
string[] data = line.Split(',');
//There aren't any lines that split to a string[] of length less than three,
//but for some reason the program kept believing there are.
//patched that leak.
if (data.Length == 3)
{
first[i] = data[0];
last[i] = data[1];
bDay[i] = Convert.ToDateTime(data[2], culture);
}
i++;
}
}
public DateTime[] quikSortTim(DateTime[] primary, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
DateTime pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (DateTime.Compare(primary[i], pivot) < 0)
i++;
while (DateTime.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (DateTime.Compare(primary[i], pivot) > 0)
i++;
while (DateTime.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
DateTime holdoverB = primary[i];
primary[i++] = primary[j];
primary[j--] = holdoverB;
string holdover = last[i - 1];
last[i] = last[j + 1];
last[j] = holdover;
holdover = first[i - 1];
first[i] = first[j + 1];
first[j] = holdover;
}
}
if (j > left)
primary = quikSortTim(primary, mode, left, j);
if (i < right)
primary = quikSortTim(primary, mode, i, right);
}
return primary;
}
public string[] quikSortStr(string[] primary, string type, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
string pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (String.Compare(primary[i], pivot) < 0)
i++;
while (String.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (String.Compare(primary[i], pivot) > 0)
i++;
while (String.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
string holdover = primary[i];
primary[i] = primary[j];
primary[j] = holdover;
if (type == "first")
{
holdover = last[i];
last[i] = last[j];
last[j] = holdover;
}
else
{
holdover = first[i];
first[i] = first[j];
first[j] = holdover;
}
DateTime holdoverBeta = bDay[i];
bDay[i] = bDay[j];
bDay[j] = holdoverBeta;
i++;
j++;
}
}
if (j > left)
primary = quikSortStr(primary, type, mode, left, j);
if (i < right)
primary = quikSortStr(primary, type, mode, i, right);
}
return primary;
}
private void frmNamArrays_SizeChanged(object sender, EventArgs e)
{
txtbxNames.Width = this.Width - 40;
txtbxNames.Height = this.Height - 157;
}
private void btnSort_Click(object sender, EventArgs e)
{
load();
switch (cbobxCategory.Text)
{
case ("First Name"):
first = quikSortStr(first, "first", order, 0, first.Length - 1);
break;
case ("Last Name"):
last = quikSortStr(last, "last", order, 0, last.Length - 1);
break;
case ("Birthday"):
bDay = quikSortTim(bDay, order, 0, bDay.Length - 1);
break;
default:
break;
}
write();
}
private void cbobxOrder_SelectedIndexChanged(object sender, EventArgs e)
{
if (cbobxOrder.Text == "Ascending")
order = "asc";
else
order = "desc";
}
private void displayfile(string name)
{
StreamReader fileData = new StreamReader(name);
txtbxNames.Lines = fileData.ReadToEnd().Split('\n');
}
private void mnuOpen_Click(object sender, EventArgs e)
{
OpenFileDialog open = new OpenFileDialog();
open.Filter = "Text Files|*.txt";
open.Title = "Select a text file...";
if (open.ShowDialog() == DialogResult.OK && open.FileName != "")
displayfile(open.FileName);
}
private void mnuExit_Click(object sender, EventArgs e)
{
this.Close();
}
}
}

You have to change the code as below in the quikSortStr method inside the if (i <= j) loop
DateTime holdoverBeta = bDay[i];
bDay[i] = bDay[j];
bDay[j] = holdoverBeta;
i++;
j--;//was: j++;
and this will fix the issue.

Thanks to saravanan for pointing out my first mistake. The out of range error was caused by an accidental incrementation of j in the wrong direction. The fixed methods are
public DateTime[] quikSortTim(DateTime[] primary, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
DateTime pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (DateTime.Compare(primary[i], pivot) < 0)
i++;
while (DateTime.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (DateTime.Compare(primary[i], pivot) > 0)
i++;
while (DateTime.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
DateTime holdoverB = primary[i];
primary[i] = primary[j];
primary[j] = holdoverB;
string holdover = last[i];
last[i] = last[j];
last[j] = holdover;
holdover = first[i];
first[i] = first[j];
first[j] = holdover;
i++;
j--;
}
}
if (j > left)
primary = quikSortTim(primary, mode, left, j);
if (i < right)
primary = quikSortTim(primary, mode, i, right);
}
return primary;
}
public string[] quikSortStr(string[] primary, string type, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
string pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (String.Compare(primary[i], pivot) < 0)
i++;
while (String.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (String.Compare(primary[i], pivot) > 0)
i++;
while (String.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
string holdover = primary[i];
primary[i] = primary[j];
primary[j] = holdover;
if (type == "first")
{
holdover = last[i];
last[i] = last[j];
last[j] = holdover;
}
else
{
holdover = first[i];
first[i] = first[j];
first[j] = holdover;
}
DateTime holdoverBeta = bDay[i];
bDay[i] = bDay[j];
bDay[j] = holdoverBeta;
i++;
j--;
}
}
if (j > left)
primary = quikSortStr(primary, type, mode, left, j);
if (i < right)
primary = quikSortStr(primary, type, mode, i, right);
}
return primary;
}
I did not find a solution for the second issue per se. I did, however, discover that all of the elements that read ",,1/1/0001" were added, and did not replace any names. Using this, I added to the array lines only the index values that did not contain "1/1/0001". I then used lines = lines.Where(s => s != null).ToArray(); to shorten lines by eliminating all of the now null-type values. The modified function is below.
private void write()
{
string[] lines = new string[first.Length];
for (int i = 0; i < lines.Length; i++)
if (bDay[i].ToString(format) != "1/1/0001")
lines[i] = first[i] + ',' + last[i] + ',' + bDay[i].ToString(format);
lines = lines.Where(s => s != null).ToArray();
txtbxNames.Clear();
txtbxNames.Lines = lines;
}
Thanks for the help. I found the resource for my solution here.
EDIT: It seems the problem is inherent in StreamReader.ReadToEnd(). I'm not sure why, but it can be completely avoided by using System.IO.File.ReadAllLines(filepath). In the original code, I would replace
StreamReader file = new StreamReader(name);
lines = file.ReadToEnd().Split('\n');
with
lines = File.ReadAllLines(name);
and add using System.IO;.

Related

Search a word in the given string in C#?

I have to find subtext in text without using builtin function of string.
public static void Main(string[] args)
{
string subtext = "polly";
string text = "polly put the katle on,polly put the katle on,polly put the katle on,we all have tea";
int i, j, found;
int strLen, wordLen;
strLen = text.Length;
wordLen = subtext.Length;
for (i = 0; i < strLen - wordLen; i++)
{
found = 1;
for (j = 0; j < wordLen; j++)
{
if (text[i + j] != subtext[j])
{
found = 0;
break;
}
}
if (found == 1)
{
Console.WriteLine(" found at index:", subtext, i);
Console.ReadLine();
}
}
}
I am not sure how long you would like to search, your current code seems to find all indexes (or at least that seems to be the intent)
Some things you could change however is instead of always starting the loop, you could validate the if the char at position i matches the first char of the subtext, and if not continue.
When you want to write the data to the console, don't forget to add the spaceholders for your arguments, like:
Console.WriteLine("found {0} at index: {1}", subtext, i);
For the rest, I guess your current implementation is okay, but you could add some validations, like ensuring that both texts are available, and if subtext is longer than the text, simply return -1 directly.
For a simple find of first index, I wrote this one up, it still looks pretty similar to yours
private static int FindIn( string text, string sub ) {
if (string.IsNullOrWhiteSpace( text ) || string.IsNullOrWhiteSpace( sub ) ) {
return string.IsNullOrWhiteSpace( sub ) ? 0 : -1;
}
if (text.Length < sub.Length) {
return -1;
}
for (int i = 0; i < text.Length - sub.Length; i++) {
if (text[i] != sub[0]) {
continue;
}
var matched = true;
for (int j = 1; j < sub.Length && i + j < text.Length; j++) {
if (text[i+j] != sub[j]) {
matched = false;
break;
}
}
if (matched) {
return i;
}
}
return -1;
}
Which you can play around with here
There are a lot of pattern-matching algorithms in this book, i will leave here c# implementation of Knuth-Morris-Pratt algorithm.
static int[] GetPrefix(string s)
{
int[] result = new int[s.Length];
result[0] = 0;
int index = 0;
for (int i = 1; i < s.Length; i++)
{
while (index >= 0 && s[index] != s[i]) { index--; }
index++;
result[i] = index;
}
return result;
}
static int FindSubstring(string pattern, string text)
{
int res = -1;
int[] pf = GetPrefix(pattern);
int index = 0;
for (int i = 0; i < text.Length; i++)
{
while (index > 0 && pattern[index] != text[i]) { index = pf[index - 1]; }
if (pattern[index] == text[i]) index++;
if (index == pattern.Length)
{
return res = i - index + 1;
}
}
return res;
}
If you are looking for all occurance of the subtect in the text you can use the following code:
public static void Main(string[] args)
{
string subtext = "polly";
string text = "polly put the katle on,polly put the katle on,polly put the katle on,we all have tea";
int index = 0;
int startPosition = 0;
bool found = false;
while (index < text.Length - 1)
{
if (subtext[0] == text[index])
{
startPosition = index;
index++;
for (int j = 1; j <= subtext.Length - 1; j++)
{
if (subtext[j] != text[index])
{
found = false;
break;
}
else
{
found = true;
}
index++;
}
}
if (found)
{
Console.WriteLine("{0} found at index: {1}", subtext, startPosition);
found = false;
}
index++;
}
Console.ReadLine();
}
If you are looking only for the first occurance add break in the "if (found)" condition

Trouble creating algorithm that modifies elements of a 2d array

I am having trouble editing the values of a 2d char array.
char[,] chrRaster = new char[4, 5];
After adding values to the array and printing it to the console, I get:
// Input example:
*****
**.**
*****
****.
I am trying to make an algorithm that replaces every '*' that is beside, under or above a '.' by a '.' and then printing this to the console.
// Output after algorithm example:
**.**
*...*
**.*.
***..
I have tried converting the 2d char array to a 2d string array and then using IndexOf('*') to replace every '*' that is beside, under or above a '.', and I also tried calculating this using a number of if and for loops without any luck.
static void Main(string[] args)
{
// Variablen
int intTestgeval = 0; // Number of times you want program to repeat
int intN = 0; // Number of rows
int intM = 0; // Number of coloms
char chrGrond; // Used to store '*' or '.'
char[,] chrRaster; // 2d char array used to store all values
// Code
try
{
intTestgeval = Int32.Parse(Console.ReadLine()); // Number of times program will repeat
if(intTestgeval > 150) // Program can not repeat more then 150 times
{
throw new Exception();
}
}
catch (Exception)
{
Environment.Exit(0);
}
intN = Controle(intN); // Number of rows ophalen
intM = Controle(intM); // Number of Coloms ophalen
chrRaster = new char[intN, intM]; // Initializing array with user input
for (int intR = 0; intR < intTestgeval; intR++) // Print 2d array to console
{
for(int intY = 0; intY < intN; intY++)
{
for(int intZ = 0; intZ < intM; intZ++)
{
chrGrond = Convert.ToChar(Console.ReadKey().KeyChar);
chrRaster[intY, intZ] = chrGrond;
}
Console.WriteLine();
}
instorten[intR] = Instorten(chrRaster, intN, intM); // Ignore this part, that's another part of my assignment not related to my question.
}
}
static int Controle( int intX )
{
try
{
intX = Int32.Parse(Console.ReadLine());
if (intX > 150 || intX < 1) // Length of row and colom can not exceed 20 and can not go lower then 1
{
throw new Exception();
}
return intX;
}
catch // Program will off if value does not meet requirements
{
Environment.Exit(0);
return intX;
}
}
// It is this part of the program I need help with. This is what I tried but can't get any further
static int Instorten(char[,] chrRaster, int intN, int intM)
{
for (int intY = 0; intY < intN; intY++)
{
for (int intZ = 0; intZ < intM; intZ++)
{
if(chrRaster[intY, intZ] == '.' && chrRaster[intY, intZ + 1] == '*' || chrRaster[intY, intZ] == '*' && chrRaster[intY, intZ + 1] == '.')
{
}
}
Console.WriteLine();
}
int intm = 0;
return intm;
}
}
One way to do this would be to make a copy of the array and then iterate over it, examining each item. If the item is a '.', then update the neighbors of this item in the original array.
To determine the neighbors, we simply add one to the row to get the neighbor below, subtract one from the row to get the neighbor above, and similarly we can get the right and left neighbors by adding/subtracting from the column value. Of course we need to ensure that we're inside the bounds of the array before doing anything.
We could write a method with this logic that might look like:
private static void ExposeDotNeighbors(char[,] input)
{
if (input == null) return;
// Make a copy of the input array that we can iterate over
// so that we don't analyze items that we've already changed
var copy = (char[,]) input.Clone();
for (var row = 0; row <= copy.GetUpperBound(0); row++)
{
for (var col = 0; col <= copy.GetUpperBound(1); col++)
{
if (copy[row, col] == '.')
{
// Update neighbors in original array
// Above = [row - 1, col], Below = [row + 1, col],
// Left = [row, col - 1], Right = [row, col + 1]
// Before updating, make sure we're inside the array bounds
if (row > 0) input[row - 1, col] = '.';
if (row < input.GetUpperBound(0)) input[row + 1, col] = '.';
if (col > 0) input[row, col - 1] = '.';
if (col < input.GetUpperBound(1)) input[row, col + 1] = '.';
}
}
}
}
We can also write some helper methods that will give us the initial array and to print an array to the console (also one that will write a header to the console):
private static char[,] GetInitialArray()
{
var initialArray = new char[4, 5];
for (var row = 0; row <= initialArray.GetUpperBound(0); row++)
{
for (var col = 0; col <= initialArray.GetUpperBound(1); col++)
{
if ((row == 1 && col == 2) || (row == 3 && col == 4))
{
initialArray[row, col] = '.';
}
else
{
initialArray[row, col] = '*';
}
}
}
return initialArray;
}
private static void PrintArrayToConsole(char[,] input)
{
if (input == null) return;
for (var row = 0; row <= input.GetUpperBound(0); row++)
{
for (var col = 0; col <= input.GetUpperBound(1); col++)
{
Console.Write(input[row, col]);
}
Console.WriteLine();
}
}
private static void WriteHeader(string headerText)
{
if (string.IsNullOrEmpty(headerText))
{
Console.Write(new string('═', Console.WindowWidth));
return;
}
Console.WriteLine('╔' + new string('═', headerText.Length + 2) + '╗');
Console.WriteLine($"║ {headerText} ║");
Console.WriteLine('╚' + new string('═', headerText.Length + 2) + '╝');
}
With these helper methods, we can then write code like:
private static void Main()
{
var chrRaster = GetInitialArray();
WriteHeader("Before");
PrintArrayToConsole(chrRaster);
ExposeDotNeighbors(chrRaster);
WriteHeader("After");
PrintArrayToConsole(chrRaster);
GetKeyFromUser("\nDone! Press any key to exit...");
}
And out output would look like:
I noticed that you also appear to be getting the values from the user, and using try/catch blocks to validate the input. A better approach might be to write a helper method that takes in a string that represents the "prompt" to the user, and a validation method that can be used to validate the input. With this, we can keep asking the user for input until they enter something valid.
Below are methods that get an integer and a character from the user, and allow the caller to pass in a function that can be used for validation. These methods will not return until the user enters valid input:
private static char GetCharFromUser(string prompt, Func<char, bool> validator = null)
{
char result;
var cursorTop = Console.CursorTop;
do
{
ClearSpecificLineAndWrite(cursorTop, prompt);
result = Console.ReadKey().KeyChar;
} while (!(validator?.Invoke(result) ?? true));
Console.WriteLine();
return result;
}
private static int GetIntFromUser(string prompt, Func<int, bool> validator = null)
{
int result;
var cursorTop = Console.CursorTop;
do
{
ClearSpecificLineAndWrite(cursorTop, prompt);
} while (!int.TryParse(Console.ReadLine(), out result) ||
!(validator?.Invoke(result) ?? true));
return result;
}
private static void ClearSpecificLineAndWrite(int cursorTop, string message)
{
Console.SetCursorPosition(0, cursorTop);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(0, cursorTop);
Console.Write(message);
}
We can then re-write our GetInitialArray method to use these methods to get the dimensions and values from the user:
private static char[,] GetInitialArray()
{
const int maxCols = 20;
const int maxRows = 20;
var numCols = GetIntFromUser(
$"How many columns do you want (1 - {maxCols}): ",
i => i > 0 && i <= maxCols);
var numRows = GetIntFromUser(
$"How many rows do you want (1 - {maxRows}): ",
i => i > 0 && i <= maxRows);
var initialArray = new char[numRows, numCols];
for (var row = 0; row <= initialArray.GetUpperBound(0); row++)
{
for (var col = 0; col <= initialArray.GetUpperBound(1); col++)
{
initialArray[row, col] = GetCharFromUser(
$"Enter value for [{row}, {col}] ('.' or '*'): ",
c => c == '.' || c == '*');
}
}
return initialArray;
}
And now our output might look like this:
If you try it, notice that you cannot enter an illegal value. The program just waits for you to read the instructions and enter a valid number or character. :)
Here is the algorithm that does what you want. I have tried to explain my code in the comments. The output will match what you're looking for.
static void Main(string[] args)
{
char STAR = '*';
char DOT = '.';
var input = new char[,]
{
{ STAR,STAR,STAR,STAR,STAR},
{ STAR,STAR,DOT,STAR,STAR},
{ STAR,STAR,STAR,STAR,STAR},
{ STAR,STAR,STAR,STAR,DOT}
};
var output = new char[4, 5];
// Copy each from input to output, checking if it touches a '.'
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 5; y ++)
{
if (input[x, y] == STAR)
{
var isDot = false;
// Check left
if (x > 0)
isDot = input[x - 1, y] == DOT;
// Check right
if (x < 3)
isDot = isDot || (input[x + 1, y] == DOT);
// Check above
if (y > 0)
isDot = isDot || (input[x, y - 1] == DOT);
// Check below
if (y < 4)
isDot = isDot || (input[x, y + 1]) == DOT;
output[x, y] = isDot ? DOT : STAR;
}
else
{
output[x, y] = input[x, y];
}
}
}
// Print output
for (int x = 0; x < 4; x ++)
{
for (int y = 0; y < 5; y ++)
{
Console.Write(output[x, y]);
}
Console.WriteLine();
}
Console.Read();
}
You can go like this :
using System;
public class chars
{
public static void Main(string[] args)
{
char[,] charArray = new char[,] {{'*','*','*','*','*'},
{'*','*','.','*','*'},
{'*','*','*','*','*'},
{'*','*','*','*','.'}};
int[,] holdIndex = new int[4, 5];
for(int i = 0; i<4; i++) // get allindexes containing '.'
{
for(int j = 0; j<5; j++)
{
if(charArray[i,j] == '.')
holdIndex[i,j] = 1;
else
holdIndex[i,j] = 0;
}
}
for(int i = 0; i<4; i++)
{
for(int j = 0; j<5; j++)
{
if(holdIndex[i,j] == 1)
{
if(i!=0)
charArray[i-1,j] = '.'; //up
if(j!=0)
charArray[i,j-1] = '.'; // left
if(j!=4)
charArray[i,j+1] = '.'; //right
if(i!=3)
charArray[i+1,j] = '.'; //down
}
}
}
for(int i = 0; i<4; i++)
{
for(int j = 0; j<5; j++)
{
Console.Write(charArray[i,j]);
}
Console.WriteLine();
}
Console.Read();
}
}

Performance issue with traversing&&filtering datagridview in c#

Currently, I am doing a log analyzer for my personal project.
My issue here is that I am new to c# and I have an performance issue with my tool.
Everytime the device(iOS) is interacted, I get an output syslog from a library and it comes in to the output handler.
public void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine, iosSyslogger form, string uuid)
{
string currentPath = System.Environment.CurrentDirectory;
bool exit = false;
if (exit == true) return;
try
{
form.BeginInvoke(new Action(() =>
{
form.insertLogText = outLine.Data;
}));
using (System.IO.StreamWriter file = new System.IO.StreamWriter(currentPath + #"\syslog" + uuid + ".txt", true))
{
file.WriteLine(outLine.Data);
}
}
catch
{
return ;
}
//*Most of the logic for outputing the log should be dealt from this output Handler
}
Then, I write the outline.Data to Data grid view. My concern is that I need to be able to search and filter through data gridview.
Curently I am using visibility = false for search filtering ( if the row does not match the given filter specification I set the row to visibility =false)
This requires the program to traverse the entire datagridview to check whether the condition is met.
Will there be any better way to filter and search within ?
(When I have thousands of lines of row, it takes at least 20 seconds to process it)
Below is the code for filtering, and searching through the results function.
private void searchResult(string term)
{
if (term != null)
{
int i = 0;
while (i < dataGridView1.Rows.Count - 1)
{
if (dataGridView1.Rows[i].Cells[3] == null)
{
i++;
continue;
}
if (dataGridView1.Rows[i].Visible == false)
{
i++;
continue;
}
else if (dataGridView1.Rows[i].Cells[2].Value.ToString().Contains(term) || dataGridView1.Rows[i].Cells[3].Value.ToString().Contains(term) || dataGridView1.Rows[i].Cells[4].Value.ToString().Contains(term))
{
string multirow = dataGridView1.Rows[i].Cells[5].Value.ToString();
int count = Convert.ToInt32(multirow);
if (count > 0)
{
int z = 0;
for (z = 0; z <= count; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
i = i + z;
}
else
{
dataGridView1.Rows[i].Visible = true;
i++;
}
}
else
{
dataGridView1.Rows[i].Visible = false;
i++;
}
}
}
}
public filteringThelist(){
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
dataGridView1.Rows[i].Visible = false;
int count1,count2,count3=0;
count1 = 1;
count2 = 1;
count3 = 1;
int z = 0;
foreach (KeyValuePair<string, string> entry in totalSelected)
{
if (entry.Value == "devicename" && dataGridView1.Rows[i].Cells[1].Value != null)
{
if (dataGridView1.Rows[i].Cells[1].Value.ToString().Trim().Equals(entry.Key.Trim()))
{
string multirow1 = dataGridView1.Rows[i].Cells[5].Value.ToString();
int counts = Convert.ToInt32(multirow1);
if (counts > 0)
{
for (z = 0; z < counts; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
}
else
{
dataGridView1.Rows[i].Visible = true;
}
}
else if (devicename.CheckedItems.Count > 1&&count1!= devicename.CheckedItems.Count)
{
count1++;
continue;
}
else
{
dataGridView1.Rows[i].Visible = false;
break;
}
}
else if (entry.Value == "process" && dataGridView1.Rows[i].Cells[2].Value != null)
{
if (dataGridView1.Rows[i].Cells[2].Value.ToString().Trim().Equals(entry.Key.Trim()))
{
string multirow1 = dataGridView1.Rows[i].Cells[5].Value.ToString();
int counts = Convert.ToInt32(multirow1);
if (counts > 0)
{
for (z = 0; z < counts; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
}
else
{
dataGridView1.Rows[i].Visible = true;
}
}
else if (processlistname.CheckedItems.Count > 1 && count2 != processlistname.CheckedItems.Count)
{
count2++;
continue;
}
else
{
dataGridView1.Rows[i].Visible = false;
break;
}
}
else if (entry.Value == "loglevel" && dataGridView1.Rows[i].Cells[3].Value != null)
{
if (dataGridView1.Rows[i].Cells[3].Value.ToString().Trim().Contains(entry.Key.Trim()))
{
string multirow1 = dataGridView1.Rows[i].Cells[5].Value.ToString();
int counts = Convert.ToInt32(multirow1);
if (counts > 0)
{
for (z = 0; z < counts; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
}
else
{
dataGridView1.Rows[i].Visible = true;
}
continue;
}
else if (loglevelCheckBox.CheckedItems.Count > 1 && count3 != loglevelCheckBox.CheckedItems.Count)
{
count3++;
continue;
}
else
{
dataGridView1.Rows[i].Visible = false;
break;
}
}
// do something with entry.Value or entry.Key
}
string multirow = dataGridView1.Rows[i].Cells[5].Value.ToString();
int count = Convert.ToInt32(multirow);
if (count > 0&& dataGridView1.Rows[i].Visible==false)
{
for (int k = 0; k <= count; k++)
{
dataGridView1.Rows[i + k].Visible = false;
}
}
i = i + z;
}
The performance problem is because your DataGridView is redrawing at each modification.
Don't fill the DataGridView directly from your Data. Rather create a DataTable and bind it to DataGridView with a BindingSource.
Then use the "Filter" property of the binding source to view extracts of dataTable in the DataGridView. The "Filter" property is a string whose content is similar to that of a WHERE SQL clause.

Adding Two Large Numbers Using Strings [duplicate]

So let me start by saying that I'm a newbie with little to moderate knowledge about C#.
Coming to the topic: I need to make a program that is able to add/subtract very large integers. Initially, used BigInt only to find out it's not allowed. There should be a logical workaround for this? I have an idea which is using "elementary school method" where you add each digit starting from right to left.
I made a string which I split into char array and added each digit from right to left(GetUpperBound-i). But it doesn't seem to work.
My Code:
string s, s2;
char[] c_arr, c_arr2;
int i, erg;
s = "1234";
s2 = "5678";
c_arr = s.ToCharArray();
c_arr2 = s2.ToCharArray();
for (i = 0; i <= c_arr.GetUpperBound(0); i++)
{
erg = c_arr[c_arr.GetUpperBound(0)-i]+c_arr2[c_arr2.GetUpperBound(0)-i];
Console.Write(erg);
}
Console.ReadKey();
There are a few things wrong with your code for the 'elementary school method'. You don't account for carry, you're adding up ascii values rather than actual values between 0-9, and you're outputting the results in the wrong order.
The code below, whilst not very elegant, does produce the correct results:
var s1 = "12345";
var s2 = "5678";
var carry = false;
var result = String.Empty;
if(s1.Length != s2.Length)
{
var diff = Math.Abs(s1.Length - s2.Length);
if(s1.Length < s2.Length)
{
s1 = String.Join("", Enumerable.Repeat("0", diff)) + s1;
}
else
{
s2 = String.Join("", Enumerable.Repeat("0", diff)) + s2;
}
}
for(int i = s1.Length-1;i >= 0; i--)
{
var augend = Convert.ToInt32(s1.Substring(i,1));
var addend = Convert.ToInt32(s2.Substring(i,1));
var sum = augend + addend;
sum += (carry ? 1 : 0);
carry = false;
if(sum > 9)
{
carry = true;
sum -= 10;
}
result = sum.ToString() + result;
}
if(carry)
{
result = "1" + result;
}
Console.WriteLine(result);
The following program can be used to add two large numbers, I have used string builder to store the result. You can add numbers containing digits upto '2,147,483,647'.
Using System;
using System.Text;
using System.Linq;
public class Test
{
public static void Main()
{
string term1="15245142151235123512352362362352351236";
string term2="1522135123612646436143613461344";
StringBuilder sum=new StringBuilder();
int n1=term1.Length;
int n2=term2.Length;
int carry=0;
int n=(n1>n2)?n1:n2;
if(n1>n2)
term2=term2.PadLeft(n1,'0');
else
term1=term1.PadLeft(n2,'0');
for(int i=n-1;i>=0;i--)
{
int value=(carry+term1[i]-48+term2[i]-48)%10;
sum.Append(value);
carry=(carry+term1[i]-48+term2[i]-48)/10;
}
char[] c=sum.ToString().ToCharArray();
Array.Reverse(c);
Console.WriteLine(c);
}
}
string Add(string s1, string s2)
{
bool carry = false;
string result = string.Empty;
if(s1[0] != '-' && s2[0] != '-')
{
if (s1.Length < s2.Length)
s1 = s1.PadLeft(s2.Length, '0');
if(s2.Length < s1.Length)
s2 = s2.PadLeft(s1.Length, '0');
for(int i = s1.Length-1; i >= 0; i--)
{
var augend = Convert.ToInt64(s1.Substring(i,1));
var addend = Convert.ToInt64(s2.Substring(i,1));
var sum = augend + addend;
sum += (carry ? 1 : 0);
carry = false;
if(sum > 9)
{
carry = true;
sum -= 10;
}
result = sum.ToString() + result;
}
if(carry)
{
result = "1" + result;
}
}
else if(s1[0] == '-' || s2[0] == '-')
{
long sum = 0;
if(s2[0] == '-')
{
//Removing negative sign
char[] MyChar = {'-'};
string NewString = s2.TrimStart(MyChar);
s2 = NewString;
if(s2.Length < s1.Length)
s2 = s2.PadLeft(s1.Length, '0');
for (int i = s1.Length - 1; i >= 0; i--)
{
var augend = Convert.ToInt64(s1.Substring(i,1));
var addend = Convert.ToInt64(s2.Substring(i,1));
if(augend >= addend)
{
sum = augend - addend;
}
else
{
int temp = i - 1;
long numberNext = Convert.ToInt64(s1.Substring(temp,1));
//if number before is 0
while(numberNext == 0)
{
temp--;
numberNext = Convert.ToInt64(s1.Substring(temp,1));
}
//taking one from the neighbor number
int a = int.Parse(s1[temp].ToString());
a--;
StringBuilder tempString = new StringBuilder(s1);
string aString = a.ToString();
tempString[temp] = Convert.ToChar(aString);
s1 = tempString.ToString();
while(temp < i)
{
temp++;
StringBuilder copyS1 = new StringBuilder(s1);
string nine = "9";
tempString[temp] = Convert.ToChar(nine);
s1 = tempString.ToString();
}
augend += 10;
sum = augend - addend;
}
result = sum.ToString() + result;
}
//Removing the zero infront of the answer
char[] zeroChar = {'0'};
string tempResult = result.TrimStart(zeroChar);
result = tempResult;
}
}
return result;
}
string Multiply(string s1, string s2)
{
string result = string.Empty;
//For multipication
bool Negative = false;
if(s1[0] == '-' && s2[0] == '-')
Negative = false;
else if(s1[0] == '-' || s2[0] == '-')
Negative = true;
char[] minusChar = {'-'};
string NewString;
NewString = s2.TrimStart(minusChar);
s2 = NewString;
NewString = s1.TrimStart(minusChar);
s1 = NewString;
List<string> resultList = new List<string>();
for(int i = s2.Length - 1; i >= 0; i--)
{
string multiplycation = string.Empty;
for (int j = s1.Length - 1; j >= 0; j--)
{
var augend = Convert.ToInt64(s1.Substring(j,1));
var addend = Convert.ToInt64(s2.Substring(i,1));
long multiply = augend * addend;
// print(multiply);
multiplycation = multiply.ToString() + multiplycation;
}
//Adding zero at the end of the multiplication
for (int k = s2.Length - 1 - i; k > 0; k--)
{
multiplycation += "0";
}
resultList.Add(multiplycation);
}
for (int i = 1; i < resultList.Count; i++)
{
resultList[0] = Add(resultList[0],resultList[i]);
}
//Finally assigning if negative negative sign in front of the number
if(Negative)
result = resultList[0].Insert(0,"-");
else
result = resultList[0];
return result;
}
string Divide(string dividend, string divisor)
{
string result = string.Empty;
int remainder = 0;
int intNumberstoGet = divisor.Length;
int currentInt = 0;
int dividing = int.Parse(dividend.Substring(currentInt,intNumberstoGet));
int intDivisor = int.Parse(divisor);
while(currentInt < dividend.Length)
{
if(dividing == 0)
{
currentInt++;
result += "0";
}
else
{
while(dividing < intDivisor)
{
intNumberstoGet++;
dividing = int.Parse(dividend.Substring(currentInt,intNumberstoGet));
}
if (dividing > 0)
{
remainder = dividing % intDivisor;
result += ((dividing - remainder) / intDivisor).ToString();
intNumberstoGet = 1;
if(currentInt < dividend.Length - 2)
currentInt += 2;
else
currentInt++;
if(currentInt != dividend.Length)
{
dividing = int.Parse(dividend.Substring(currentInt,intNumberstoGet));
remainder *= 10;
dividing += remainder;
}
}
}
}
return result;
}
Here you go. Another example. It's 10 to 30 times faster than the accepted answer.
static string AddNumStr(string v1, string v2)
{
var v1Len = v1.Length;
var v2Len = v2.Length;
var count = Math.Max(v1Len, v2Len);
var answ = new char[count + 1];
while (count >= 0) answ[count--] = (char)((v1Len > 0 ? v1[--v1Len] & 0xF:0) + (v2Len>0 ? v2[--v2Len]&0xF : 0));
for (var i = answ.Length - 1; i >= 0; i--)
{
if (answ[i] > 9)
{
answ[i - 1]++;
answ[i] -= (char)10;
}
answ[i] = (char)(answ[i] | 48);
}
return new string(answ).TrimStart('0');
}
Below SO question has some interesting approaches. Though the answer is in Java, but you will surely get to know what needs to be done.
How to handle very large numbers in Java without using java.math.BigInteger
public static int[] addTwoNumbers(string s1, string s2)
{
char[] num1 = s1.ToCharArray();
char[] num2 = s2.ToCharArray();
int sum = 0;
int carry = 0;
int size = (s1.Length > s2.Length) ? s1.Length + 1 : s2.Length + 1;
int[] result = new int[size];
int index = size - 1;
int num1index = num1.Length - 1;
int num2index = num2.Length - 1;
while (true)
{
if (num1index >= 0 && num2index >= 0)
{
sum = (num1[num1index]-'0') + (num2[num2index]-'0') + carry;
}
else if(num1index< 0 && num2index >= 0)
{
sum = (num2[num2index]-'0') + carry;
}
else if (num1index >= 0 && num2index < 0)
{
sum = (num1[num1index]-'0') + carry;
}
else { break; }
carry = sum /10;
result[index] = sum % 10;
index--;
num1index--;
num2index--;
}
if(carry>0)
{
result[index] = carry;
}
return result;
}

How to process an array correctly

Here's the part 1 of my question, if you wanna check the background of this question :
Detecting brackets in input string
Forgive me if the title doesn't match, since I also confused how to name it appropriately to picture my problem. If anyone knows a more appropriate title, feel free to edit.
So, given below code (my own code) :
private const int PARTICLE_EACH_CHAR = 4;
/*ProcessBarLines : string s only contains numbers, b, [, and ]*/
private int ProcessBarLines(Canvas canvas, string s, int lastLineAboveNotation)
{
List<int> bracket = new List<int>();
List<int> other = new List<int>();
int currentCloseNumber = 0;
int currentOpenNumber = 0;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == '[')
{
bracket.Add(i);
currentOpenNumber++;
if (i - 1 > 0 && s[i - 1] != '[')
{
currentOpenNumber = 1;
}
}
else if (s[i] == ']')
{
bracket.Add(i);
currentCloseNumber++;
if (i + 1 >= s.Length || s[i + 1] != ']' || currentOpenNumber == currentCloseNumber)
{
int min = bracket.Count - (currentCloseNumber * 2);
int max = bracket[bracket.Count - 1];
List<int> proc = new List<int>();
int firstIndex = -1;
int lastIndex = -1;
for (int ii = 0; ii < other.Count; ii++)
{
if (other[ii] > min && other[ii] < max)
{
proc.Add(other[ii]);
if (firstIndex == -1)
{
firstIndex = ii;
lastIndex = ii;
}
else
{
lastIndex = ii;
}
}
}
double leftPixel = firstIndex * widthEachChar;
double rightPixel = (lastIndex * widthEachChar) + widthEachChar;
DrawLine(canvas, currentCloseNumber, leftPixel,
rightPixel, lastLineAboveNotation * heightEachChar / PARTICLE_EACH_CHAR);
lastLineAboveNotation += currentCloseNumber - 1;
currentOpenNumber -= currentCloseNumber;
currentCloseNumber = 0;
}
}
else
{
other.Add(i);
}
}
return lastLineAboveNotation + 1;
}
Here's the test cases :
Picture 1 & 2 is the correct answer, and picture 3 is the wrong answer. Picture 3 should have a line, just like inverted from number 2, but, apparently, (if you look closely) the line is drawn on the right, but it should be on the left to be correct (above 0).
I figured, the problem is, I'm quite sure on the "min". Since it doesn't give the correct starting value.
Any idea on this? Feel free to clarify anything. It's used for writing numeric musical scores.
Btw, DrawLine() just meant to draw the line above the numbers, it's not the problem.
Finally! I found it!
private int ProcessBarLines(Canvas canvas, string s, int lastLineAboveNotation)
{
List<int> bracket = new List<int>();
List<int> other = new List<int>();
int currentCloseNumber = 0;
int currentOpenNumber = 0;
int space = 0;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == '[')
{
bracket.Add(i);
currentOpenNumber++;
if (i - 1 > 0 && s[i - 1] != '[')
{
currentOpenNumber = 1;
}
}
else if (s[i] == ']')
{
bracket.Add(i);
currentCloseNumber++;
if (i + 1 >= s.Length || s[i + 1] != ']' || currentOpenNumber == currentCloseNumber)
{
int min = bracket[Math.Max(bracket.Count - ((currentCloseNumber * 2) + space), 0)];
int max = bracket[bracket.Count - 1];
space = max - min - 1;
List<int> proc = new List<int>();
int firstIndex = -1;
int lastIndex = -1;
for (int ii = 0; ii < other.Count; ii++)
{
if (other[ii] > min && other[ii] < max)
{
proc.Add(other[ii]);
other[ii] = -1;
if (firstIndex == -1)
{
firstIndex = ii;
lastIndex = ii;
}
else
{
lastIndex = ii;
}
}
}
double leftPixel = firstIndex * widthEachChar;
double rightPixel = (lastIndex * widthEachChar) + widthEachChar;
DrawLine(canvas, currentCloseNumber, leftPixel,
rightPixel, lastLineAboveNotation * heightEachChar / PARTICLE_EACH_CHAR);
lastLineAboveNotation += 1;
currentOpenNumber -= currentCloseNumber;
currentCloseNumber = 0;
}
}
else
{
other.Add(i);
}
}
return lastLineAboveNotation + 1;
}
If someone got a more efficient code, please let us know!

Categories

Resources