C# sum problems - c#

I am using the below code to get the sum of a column in a data grid view.
private void button16_Click(object sender, EventArgs e)
{
int sum = 0;
for (int i = 0; i < dataGridView4.Rows.Count; ++i)
{
sum += Convert.ToInt32(dataGridView4.Rows[i].Cells[10].Value);
}
try
{
decimal tot = 0;
for (int i=0; i <= dataGridView4.RowCount -1; i++)
{
tot += Convert.ToDecimal (dataGridView4.Rows[i].Cells[10].Value);
}
if (tot==0) {}
textBox34.Text = tot.ToString();
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I am getting the error message
Input string was not in a correct format.
ِI found that the problem is in the formatting. Becasue the SQL server data type for that column is money. and the SQL server changes any number I save to this format. 00.0000
For example, If I save 10 SQL server saves it as 10.0000
If I remove the (.) I get no errors.
If I try to sum 10.0000 + 3.0000 it never works out.
Any ideas?

Your problem is that you're trying to convert a value with a decimal point from string to int. When using the money datatype in your DB, the best datatype to use in your code will be the decimal type. See the answer on What is the best data type to use for money in C#
So doing:
int val = Convert.ToInt32("10.00");
Will yield the following error (which is what you're receiving):
Unhandled Exception: System.FormatException: Input string was not in a
correct format.
You can convert the value using the Convert.ToDecimal() method:
decimal val = Convert.ToDecimal("10.00");
If you want to remove the decimal portion of the value, you can use one of the following methods based on your requirements:
Math.Floor
Math.Ceiling
Math.Round
Math.Truncate
For example:
decimal val2 = Math.Round(val);
Or:
decimal val2 = Math.Truncate(val);
If you simply want to return the value as a string but without the decimal portion, you can do as follows:
decimal val = Convert.ToDecimal("10.00");
Console.WriteLine(val.ToString("0.#"));
Edit:
So in your code, change:
int sum = 0;
for (int i = 0; i < dataGridView4.Rows.Count; ++i)
{
sum += Convert.ToInt32(dataGridView4.Rows[i].Cells[10].Value);
}
For:
decimal sum = 0;
for (int i = 0; i < dataGridView4.Rows.Count; ++i)
{
sum += Convert.ToDecimal(dataGridView4.Rows[i].Cells[10].Value);
}

Related

Getting the column totals in a 2D array but it always throws FormatException using C#

I am planning to get an array of the averages of each column.
But my app crashes at sum[j] += int.Parse(csvArray[i,j]); due to a FormatException. I have tried using Convert.ToDouble and Double.Parse but it still throws that exception.
The increments in the for loop start at 1 because Row 0 and Column 0 of the CSV array are strings (names and timestamps). For the divisor or total count of the fields that have values per column, I only count the fields that are not BLANK, hence the IF statement. I think I need help at handling the exception.
Below is the my existing for the method of getting the averages.
public void getColumnAverages(string filePath)
{
int col = colCount(filePath);
int row = rowCount(filePath);
string[,] csvArray = csvToArray(filePath);
int[] count = new int[col];
int[] sum = new int[col];
double[] average = new double[col];
for (int i = 1; i < row; i++)
{
for (int j = 1; j < col; j++)
{
if (csvArray[i,j] != " ")
{
sum[j] += int.Parse(csvArray[i,j]);
count[j]++;
}
}
}
for (int i = 0; i < average.Length; i++)
{
average[i] = (sum[i] + 0.0) / count[i];
}
foreach(double d in average)
{
System.Diagnostics.Debug.Write(d);
}
}
}
I have uploaded the CSV file that I use when I test the prototype. It has BLANK values on some columns. Was my existing IF statement unable to handle that case?
There are also entries like this 1.324556-e09due to the number of decimals I think. I guess I have to trim it in the csvToArray(filePath) method or are there other efficient ways? Thanks a million!
So there are a few problems with your code. The main reason for your format exception is that after looking at your CSV file your numbers are surrounded by quotes. Now I can't see from your code exactly how you convert your CSV file to an array but I'm guessing that you don't clear these out - I didn't when I first ran with your CSV and experienced the exact same error.
I then ran into an error because some of the values in your CSV are decimal, so the datatype int can't be used. I'm assuming that you still want the averages of these columns so in my slightly revised verion of your method I change the arrays used to be of type double.
AS #musefan suggested, I have also changed the check for empty places to use the IsNullOrWhiteSpace method.
Finally when you output your results you receive a NaN for the first value in the averages column, this is because when you don't take into account that you never populate the first position of your arrays so as not to process the string values. I'm unsure how you'd best like to correct this behaviour as I'm not sure of the intended purpose - this might be okay - so I've not made any changes to this for the moment, pop a mention in the comments if you want help on how to sort this!
So here is the updated method:
public static void getColumnAverages(string filePath)
{
// Differs from the current implementation, reads a file in as text and
// splits by a defined delim into an array
var filePaths = #"C:\test.csv";
var csvArray = File.ReadLines(filePaths).Select(x => x.Split(',')).ToArray();
// Differs from the current implementation
var col = csvArray[0].Length;
var row = csvArray.Length;
// Update variables to use doubles
double[] count = new double[col];
double[] sum = new double[col];
double[] average = new double[col];
Console.WriteLine("Started");
for (int i = 1; i < row; i++)
{
for (int j = 1; j < col; j++)
{
// Remove the quotes from your array
var current = csvArray[i][j].Replace("\"", "");
// Added the Method IsNullOrWhiteSpace
if (!string.IsNullOrWhiteSpace(current))
{
// Parse as double not int to account for dec. values
sum[j] += double.Parse(current);
count[j]++;
}
}
}
for (int i = 0; i < average.Length; i++)
{
average[i] = (sum[i] + 0.0) / count[i];
}
foreach (double d in average)
{
System.Diagnostics.Debug.Write(d + "\n");
}
}

Having the nth char based on a variable not working as expected

So I have pow - a list containing numbers. I have to examine other numbers like this: Get all the digits and sum the numbers from pow having the same index as the certain digit.
So if I check number 4552 I need to get pow[4]+pow[5]+pow[5]+pow[2]. Because I'm a noob I try to convert the number to string, get the characters with loop and then convert back to int to get the index. So the code is as follows for getting the sums between 4550 and 4559:
for (int i = 4550; i < 4560; i++)
{
int sum = 0;
for (int j = 0; j < i.ToString().Length; j++)
{
sum += pows[Convert.ToInt32(i.ToString()[j])]; //here is the error - index was out of range
//do something with sum (like store it in another list)
}
}
So what is wrong with that?
EDIT: To avoid confusion... pow has 10 elements, from indexes 0-9.
SOLUTION: The issue with my code was that I got the character code not the digit itself, thanks Steve Lillis. Though the solution provided by Dmitry Bychenko is far more superior to my attempt. Thank you all.
What you're looking for is similar to a digital root:
Modulus (% in C#) is easier and faster than conversion to string:
public static int DigitalRootIndex(IList<int> list, int value) {
if (value < 0)
value = -value;
int result = 0;
// for value == 4552
// result == list[4] + list[5] + list[5] + list[2]
while (value > 0) {
int index = value % 10;
result += list[index];
value /= 10;
}
return result;
}
...
int test = DigitalRootIndex(pow, 4552);
This bit of code gets a single character such as '4' which is character code 59:
c = i.ToString()[j]
Then this bit of code turns that char into an integer. It doesn't parse it like you're expecting, so the result for '4' is 59, not 4:
Convert.ToInt32(c)
Do this instead:
int.Parse(c.ToString())
Something like this (quick and dirty try)?
int currentDigit;
int sum;
for (int i = 4550; i < 4560; i++)
{
sum = 0;
currentDigit = i;
while (currentDigit > 0)
{
if (pow.Count > (currentDigit % 10))
{
sum += pow[((currentDigit % 10))];
}
}
}
Note that lists have zero based index so when you do pow[1], you are actually accessing second element in the list. Is that what you want?

How to pass value from one method to another?

I am working on a employee paycheck calculator using several private methods. The methods will determine overtime hours and regular hours. I also must create methods for regular pay and overtime pay. My question is can I feed the results from the hours methods into the methods that will determine pay? If that is possible, how would it work? The method in question is CalculateBasePayAmount--can I pass a result from another method into here?
Here is a look at what I've got so far. Thanks for any help anyone could provide!
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
//Determine Hours Method
private decimal DetermineBasePayHours(decimal parhoursWorked)
{
decimal baseHours = 0;
decimal overtimeHours = 0;
if (parhoursWorked <= 40)
{
baseHours = parhoursWorked;
}
else if (parhoursWorked > 40)
{
overtimeHours = parhoursWorked - 40;
baseHours = parhoursWorked - overtimeHours ;
}
return baseHours;
}
private decimal DetermineOverTimeHours(decimal parHoursWorked, string parCategory)
{
decimal overtimeHours = 0;
if (parHoursWorked > 40 && parCategory!="MGR")
{
overtimeHours = parHoursWorked - 40;
}
return overtimeHours;
}
private decimal CalculateBasePayAmount(decimal basePayHours, string parCategory)
{
decimal basePay = 0;
decimal mgrWage = 20;
decimal salesWage = 15;
decimal staffWage = 10;
basePayHours= DetermineBasePayHours(basePayHours);
if(parCategory == "MGR" && basePayHours > 40)
{
basePay = 40 * mgrWage;
}
else
{
basePay = basePayHours * mgrWage;
}
if (parCategory =="SR")
{
basePay = basePayHours * salesWage;
}
else if (parCategory == "STF")
{
basePay = basePayHours * staffWage;
}
return basePay;
}
protected void butCalcPay_Click(object sender, EventArgs e)
{
////1. Declare Variables
//decimal mgrWage = 20;
//decimal salesWage = 15;
//decimal staffWage = 10;
//decimal basePay = 0M;
//decimal salesOvertime = 22.50M;
//decimal staffOvertime = 15;
//decimal overtimeHours = 0;
//decimal overtimePay = 0;
//decimal totalPay = 0;
decimal totalHours = 0;
decimal bpHours;
decimal otHours;
string empCat;
decimal basePay;
//2. Get Values for Variables
totalHours = Convert.ToDecimal(txtNumberHours.Text);
empCat = Convert.ToString(ddlCategory.SelectedValue);
// 3. Methods Called
bpHours = DetermineBasePayHours(totalHours);
otHours = DetermineOverTimeHours(totalHours, empCat);
basePay = CalculateBasePayAmount(totalHours, empCat);
// 4. Display Results
lblbasePay.Text = "Base Pay " + basePay.ToString("C");e here
can I feed the results from the hours methods into the methods that will determine pay?
In a manner of speaking, yes. Though I think the confusion is coming from the way you describe it and the terminology you use.
It's not entirely clear to me what specific values you're looking for in this case, but it looks like your methods essentially just accept some values, run some calculations, and return some values. Any code which call those functions will then get those returned values and can use them to call other functions. As a contrived example:
private int Method1(int someValue)
{
// perform some calculation, then...
return anotherValue;
}
private int Method2(int someValue)
{
// perform some calculation, then...
return anotherValue;
}
Then consuming code would be able to use those functions to perform larger calculations:
var calculatedValue = Method1(5);
var furtherCalculatedValue = Method2(calculatedValue);
This essentially "feeds the results" of the first function into the second function, in the sense that the result of the first function is then used as an input for the second function. The functions don't have any knowledge of each other, they don't "feed data to each other", in this case they simply return values based on calculations. Consuming code can choose to use the result of one function as a parameter to another function.
You do need to read more on programming and how/why we have methods that return values that the ones you mentioned above. Using your code above you'll want to use their values like this:
// basePayHours is the decimal amount returned by DetermineBasePayHours.
var basePayHours = DetermineBasePayHours(parhoursWorked);
// overTimeHours is the decimal amount returned by DetermineOverTimeHours.
var overTimeHours = DetermineOverTimeHours(parHoursWorked, parCategory);
// basePayAmount is the decimal amount returned by CalculateBasePayAmount.
var basePayAmount = CalculateBasePayAmount(basePayHours, parCategory);
delegate can also be used when a method is needed from another one .

Converting a string into BigInteger

I have the following code that creates a very big number (BigInteger) which is converted then into a string.
// It's a console application.
BigInteger bi = 2;
for (int i = 0; i < 1234; i++)
{
bi *= 2;
}
string myBigIntegerNumber = bi.ToString();
Console.WriteLine(myBigIntegerNumber);
I know that for converting to int we can use Convert.ToInt32 and converting to long we use Convert.ToInt64, but what's about converting to BigInteger?
How can I convert a string (that represents a very very long number) to BigInteger?
Use BigInteger.Parse() method.
Converts the string representation of a number in a specified style to
its BigInteger equivalent.
BigInteger bi = 2;
for(int i = 0; i < 1234; i++)
{
bi *= 2;
}
var myBigIntegerNumber = bi.ToString();
Console.WriteLine(BigInteger.Parse(myBigIntegerNumber));
Also you can check BigInteger.TryParse() method with your conversation is successful or not.
Tries to convert the string representation of a number to its
BigInteger equivalent, and returns a value that indicates whether the
conversion succeeded.
Here is another approach which is faster compared to BigInteger.Parse()
public static BigInteger ToBigInteger(string value)
{
BigInteger result = 0;
for (int i = 0; i < value.Length; i++)
{
result = result * 10 + (value[i] - '0');
}
return result;
}

C# parse value from string

I would like to parse string value like this :
.02234
-.23455
-1.23345
2.
.3
but i get an FormatException
for (int i = 1; i < 7; i++)
{
var item = Double.Parse(reader.ReadLine(44).Substring(8 * i, 8));
richTextBox1.Text += item.ToString() + "\n";
}
the problem that i should convert this numbers like "0.2" or "-.0541" to double or any value type to work with it !!!
Since you've made a comment that , is the decimal separator in your locale, there is a better option than doing a string-replace of . to ,; tell the Double.Parse() method to use a different number format.
See the MSDN doc for Parse(String s). Especially, note the following:
The s parameter is interpreted using
the formatting information in a
NumberFormatInfo object that is
initialized for the current thread
culture. For more information, see
CurrentInfo. To parse a string using
the formatting information of some
other culture, call the
Double.Parse(String, IFormatProvider)
or Double.Parse(String, NumberStyles,
IFormatProvider) method.
Assuming your current thread culture is using a number format that considers , to be the decimal separator (French/France fr-FR, for example), you must pass an IFormatProvider to the Parse() method that defines . as the decimal separator. Conveniently, the "no culture in particular" culture, CultureInfo.InvariantCulture, does just this.
So this code should parse successfully:
for (int i = 1; i < 7; i++)
{
// Assume the substring of ReadLine() contains "-.23455", for example
var item = Double.Parse(reader.ReadLine(44).Substring(8 * i, 8), CultureInfo.InvariantCulture);
richTextBox1.Text += item.ToString() + "\n";
}
You're passing a string that isn't a double, something like 1.a or 1. .3 (1 string representing 2 numbers)
You can use Double.TryParse() and it will not throw an exception but return true/false if it was successful or not. It might make the flow easer.
reader.ReadLine(44).Substring(8 * i, 8).ToString()
You won't need the .ToString(). Verify that this actually returns the value you're looking for.
The format exception is throw because the value it's trying to parse is not valid!
My first guess is that the argument you're passing is not in fact a double.
Might try to split up your calls, and toss in a breakpoint to see what's actually going on.
for (int i = 1; i < 7; i++)
{
string textNum = reader.ReadLine(44).Substring(8 * i, 8);
// add a breakpoint on the next line, then look at textNum. I bet it's not what you hoped.
double item = double.Parse(textNum);
richTextBox1.Text += string.Format("{0}\n", item);
}
Use Double.TryParse() and test to see if the value was successfully parsed into your local variable like this:
for (int i = 1; i < 7; i++)
{
double value = 0;
string input = reader.ReadLine(44).Substring(8 * i, 8);
if (Double.TryParse(input, out value))
{
richTextBox1.Text += value.ToString() + "\n";
}
else
{
richTextBox1.Text = "Invalid double entered.";
}
}
i just find a solution to the problem ( replace to dot with comma ) :
public Double[] GridValues(int fromline)
{
Double[] values = new Double[7];
for (int i = 1; i < 7; i++)
{
string input = ReadLine(fromline).Substring(8 * i, 8).Replace(".", ",");
values[i-1] = double.Parse(input);
}
return values;
}

Categories