Pass data from a CSVReader to a method inside a loop - c#

I have a CSV with the following data
month,year,speed
12,2010,76
2,2000,45
12,1940,30
and I'm loading using a 3rd party that reads it. In short, it is a CSVReader class and able to get the data from a file called input like this
List<Dictionary<string, object>> data = CSVReader.Read("input");
Then, using a for loop I'm capable of retrieving the data this way
for(var i=0; i < data.Count; i++) {
print ("month" + data[i]["month"] + " " +
"year" + data[i]["year"] + " " +
"speed " + data[i]["speed"]);
}
Except inside of the for loop I want to pass each year and month (one by one) to another function that takes as argument something like doubles (not objects) and i don't know how
for(var i=0; i < data.Count; i++) {
// Get month and year
function(month, year);
}

If I correctly interpret this and your question is: "How do I pass a value of type object to a function that takes a parameter of type double?", then you could either:
1) Cast the value
like this:
for (var i = 0; i < data.Count; i++) {
double month = (double)data[i]["month"];
// Same for year.
function(month, year);
}
Note that if the values you are casting cannot be casted to the target type (i.e., csv you are reading contains some corrupted rows), that would cause an exception to be thrown. If you're certain that won't be the problem, you can just do this, however, if you want to be sure, you can go with the option 2 which is
2) Use the as operator
like this:
for (var i = 0; i < data.Count; i++) {
double? month = data[i]["month"] as double?;
if (!month.HasValue) {
Console.WriteLine($"Month value on line {i + 1} is corrupted; Skipping...");
break;
}
// Same for year.
function(month.Value, year.Value);
}
In this case if the value is not of the double type, the month will be assigned the value of null (that's why we use the nullable double? type). That allows you to check whether the conversion was successful without having to handle possible exceptions.

Related

Can't figure out how to correct my array?

Here is my code. I get a red line under StockPrices saying that it can not implicitly convert type decimal to int. Which I understand since StockPrices Array is set as a decimal. I can't figure out how to convert it. (If you find any other issues, please call it out. I'm still learning!)
public int FindNumTimesNegativePriceChange()
{
int difference = 0;
decimal[] negativeChange = new decimal[StockPrices];
for (int i = 0; i < StockPrices.Length - 1; ++i)
{
difference = (int)(StockPrices[i + 1] - StockPrices[i]);
if (difference < 0)
{
negativeChange++;
}
}
return negativeChange;
Currently no result is returned.
If you want a new array with the same length as an existing array, use the Length property for the source array, not the array itself:
new decimal[StockPrices.Length];
But I'm not sure that is what you are looking for at all.
You want a counter, so difference only needs to be an int in this case.
The next issue is that you are explicitly casting decimal values to an int which means you will lose precision. Other data types would throw an exception in this case but decimal allows it and will truncate the values, not round them.
For stock prices, commonly the changes are less than 1, so in this business domain precision is usually important.
If it is your intention to only count whole integer losses then you should include a comment in the code, mainly because explicit casting like this is a common code mistake, comments are a great way to prevent future code reviewers from editing your logic to correct what looks like a mistake.
Depending on your source code management practises, it can be a good idea to include a reference to the documentation / task / change request that is the authority for this logic.
public int FindNumTimesNegativePriceChange()
{
int difference = 0;
int negativeChange = 0;
for (int i = 0; i < StockPrices.Length - 1; ++i)
{
// #11032: Only counting whole dollar changes
difference = (int)(StockPrices[i + 1] - StockPrices[i]);
if (difference < 0)
{
negativeChange++;
}
}
return negativeChange;
}
A final peer review item, this method processes a single input, but currently that input needs to be managed outside of the scope of this method. In this case StockPrices must be declared at the member level, but this logic is easier to isolate and test if you refactor it to pass through the source array:
public int FindNumTimesNegativePriceChange(decimal[] stockPrices)
{
decimal difference = 0;
int negativeChange = 0;
for (int i = 0; i < stockPrices.Length - 1; ++i)
{
difference = stockPrices[i + 1] - stockPrices[i];
if (difference < 0)
{
negativeChange++;
}
}
return negativeChange;
}
This version also computes the difference (delta) as a decimal
Fiddle: https://dotnetfiddle.net/XAyFnm

C# Pull items from array based on string

Not sure if this is the best way to do this but I've created a 2D array from values in an excel file that i want to use as variables within my application that control where to look for things like file paths and files.
The array is built and all data from the file is contained within it:
for (int i = 0; i <= bindingSourceConfig.Count - 1; i++) // for each row in the binding source data
{
for (int j = 0; j <= 2 - 1; j++) // for each column, only need one and 2
{
System_Var_Array[i, j] = (bindingSourceConfig.DataSource as DataTable).Rows[i][j].ToString();
}
}
Now i want to be able to look in the array for my variable say "Project_Directory" and have it return "C:\Users\User\Dropbox\default\master\support"
Is this even possible?
EDIT 1:
Purpose of doing it this way is to make an easily customizable/configurable multi project environment where by anyone can simply edit the paths in the excel file and import that file into the application.
I can not in my incompetence see a way of setting these 'variables' at a class level without first extracting the 'variable' and the 'value' from the excel data.
Is there a simple way of looking up the 'variable' in bindingSource?
EDIT 2:
debugger image
var name = "Project_Directory";
string value = null;
for (int i = 0; i<System_Var_Array.GetLength(0); i++) {
if (System_Var_Array[i,0]==name) {
value = System_Var_Array[i,1];
break;
}
}
After the loop stop, value will contain the data you need, assuming it exists (otherwise it will be null. A far simpler approach will be using Dictionary<string,string>, if you generate it with
var systemVars = new Dictionary<string,string>();
var dt = bindingSourceConfig.DataSource as DataTable;
for (int i = 0; i < bindingSourceConfig.Count; i++) // for each row in the binding source data
{
systemVars[dt.Rows[i][0].ToString()] = dt.Rows[i][1].ToString();
}
then to get the value for "Project_Directory", simply call
var value = systemVars["Project_Directory"];
You should use an appsettings file for this instead, it's the dotnet standard solution for this sort of thing. Please see https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration.

How to add more iterations in a for loop C# Make my loop pick up more

I am trying to show multiple things in a textbox in my software and its just printing out 1 / 5
I think I got the for loop all mixed up so here is how it looks
var getTopFive = new FirefoxDriver();
getTopFive.Navigate().GoToUrl("https://www.tradingview.com/");
IList<IWebElement> movies = getTopFive.FindElements(By.CssSelector("tbody tr"));
for (int i = 0; i < 1; ++i)
{
activeTextBox.Text = movies[i].Text;
}
This is what I tried and failed with.
I tried adding another
activeTextBox.Text = movies[i].Text;
Which did not work
I also tried adding a second block of the same code showed at the top but with a different name for the int etc.
Then I tried adding a else if below it which gave me another error.
So my question is, how do I make the loop go through all the 5 items instead of just showing the first one which it does by this line of code right here.
for (int i = 0; i < 1; ++i)
{
activeTextBox.Text = movies[i].Text;
}
There are two issues here. The first is your for loop is only going to happen once because for(int i = 0; i < 1; i++).
To loop more than once, you need to change to 1 to something else. If you want it dynamic, use for(int i = 0; i < movies.Count; i++).
The second issue is activeTextBox.Text is being over-written each time you write to it. No matter how many times you repeat the loop or the line, the only thing that text box will show is the last item in the loop.
If you want it to show all items, you need to do something like:
activeTextBox.Text += movies[i].Text + "\n";
The \n will put each movie on a separate line - you could use a hyphen or similar to separate each item.
IList has a property called Count. This property returns the number of elements in the list. Use it in your loop like this to show all movies:
for (int i = 0; i < movies.Count; i++)
{
activeTextBox.Text = movies[i].Text;
}
A second way is to use a foreach loop like this:
foreach (IWebElement WebElement in movies)
{
activeTextBox.Text = WebElement.Text;
}
Remember you are overwriting your text each loop. So in the end your text will be the last item of your loop. If you want to add the names behind each other do it like this (seperated with a minus)
activeTextBox.Text += " - " + movies[i].Text;
or this
activeTextBox.Text += " - " + WebElement.Text
clear the Text before your loop with
activeTextBox.Text.Clear();
Try using this code (don't forget to add using System.Linq;):
activeTextBox.Text = string.Join("; ", movies.Select(x => x.Text));
Explanation:
movies.Select(x => x.Text) takes every IWebElement (movie) and return its Text property. So you end up with a list of movie names instead of IWebElement objects.
Next, you join those movies together into a single string, separated by semicolon. (string.Join("; ", ...))
And then you assign the result to the activeTextBox.

retrieving number value from datagridview C#

I am trying to retrieve a numerical value from datagridview. The data type for both the value in the table, and the variable (weeklyTotal), are integer. Also I am trying to cast it into integer. I looked through the whole website for similar problems, and yet none of the solutions were helpful. The error message that I am getting is “when casting form a number, the value must be less than infinity”. I went back to my table more than one time to make sure that I don’t have invalid value.
it's a runtime error and the IDE always point at this line
weeklyTotal += (int)dataGridView1.Rows[i].Cells[1].Value;
for (int i = 0; i < this.dataGridView1.Rows.Count; i++)
{
sdate = dataGridView1.Rows[i].Cells[2].Value.ToString();
ddate = dataGridView1.Rows[i].Cells[3].Value.ToString();
if ((weekFirstDay <= Convert.ToInt32(sdate) &&
Convert.ToInt32(sdate) <= (weekFirstDay + 7))||(weekFirstDay <= `Convert.ToInt32(ddate) &&`
Convert.ToInt32(ddate) <= (weekFirstDay + 7)))
{
dataGridView1.Rows[i].Selected = true;
dataGridView1.Rows[i].Visible = true;
weeklyTotal += (int)dataGridView1.Rows[i].Cells[1].Value;
//weeklyTotalString = dataGridView1.Rows[i].Cells[1].Value.ToString();
//weeklyTotal += Convert.ToInt32(weeklyTotalString);
}
else
That's because the following won't cast your cell value to the int type:
(int) dataGridView1.Rows[i].Cells[1].Value
You're just taking the string saying "hey compiler, please treat it as an int type", but it will still be a string type underneath. Use the Convert.ToInt32 method like you did earlier.
weeklyTotal += Convert.ToInt32(dataGridView1.Rows[i].Cells[1].Value);
int num = Convert.ToInt32(dgv.Rows[i].Cells["col_name"].Value);
You may be trying to to an (int) cast on a DBNull value. I'm assuming that you populating the datagridview with data from the database.
Try this:
if(dataGridView1.Rows[i].Cells[1].Value != DBNull.Value)
{
weeklyTotal += (int)dataGridView1.Rows[i].Cells[1].Value;
}

Programatically reference ascending variable names (var1, var2, ... )

I'm currently coding a project that can take up to 200 entries of a specific product, as determined by user input. Basically, my GUI loads, and I use jQuery to dynamically build the entries whenever there is a change to the amount field. When using jQuery, I simply give each of them ids in the form of variable1, variable2, ...., variableX (where X is the amount of entries indicated). Small snippet of code to clarify:
for(var i = 1;i <= amount_selected; i++) {
$('table_name tr:last').after('<tr><td><input type="text" id="variable' + i + '"></td></tr>');
}
Now when I try to move to the back end, I'm trying to reference these variable names by putting them in a list. I went ahead and put them in a list of HtmlInputText, to call the Variable names from the list itself. (This would save having to call all (up to 200) methods manually, which is really not an option).
So what I did (in C#) was:
List<HtmlInputText> listvar = new List<HtmlInputText>();
for(int i = 1; i <= amount_selected; i++) {
string j = "variable" + Convert.ToString(i);
HtmlInputText x = j;
listvar.Add((x));
samplemethod(listvar[i]);
}
But it's not working at all. Does anyone have any ideas as to how this would be done, without doing so manually? I know my logic might be completely off, but hopefully this illustrates at least what I'm attempting to do.
I'm assuming these inputs are in a form? If you're submitting then you can access the text boxes from the Request object:
List<string> results = new List<string>();
for (int i = 1; i <= amount_selected; i++)
{
string s = String.Format("{0}", Request.Form["variable" + Convert.ToString(i)]);
results.Add(s);
}
you could do $("#variable" + Convert.ToString(i)).val()

Categories