c# position counter in a stream reader - c#

Developing a small quiz application, thus far I have a text file containing two example questions to see if i can get it working properly before adding more. There are 5 question levels of increasing difficulty, each of these levels contains 10 questions
I'm using a streamreader to read my level 1 questions in from the text file, it reads the first question in fine and the program reads user input and compares it to the answer. If correct the user will move to the next level, but if incorrect I want the program to ask the second question in the file - but it continues to read the first.
I have
static int pos = 0;
serving as my position counter for the reader, but whenever I try to include the position when addressing my struct in the reader like
_question1[pos].q_No = Convert.ToInt32(sreader.ReadLine());
I get an error message:
Cannot apply indexing with [] to an expression of type
'Quiz_Application.Program.question1'
Variables n stuff:
static question1[] _questions1 = new question1[10];
static question2[] _questions2 = new question2[10];
static question3[] _questions3 = new question3[10];
static question4[] _questions4 = new question4[10];
static question5[] _questions5 = new question5[10];
static int score = 0;
static int asked = 0;
static int pos = 0;
static int user_input = 0;
static int user_level = 1;
struct question1
{
public int q_No;
public string Question;
public string Choices;
public int Answer;
}
My reader:
static void QuestionReader_Level1()
{
Console.Clear();
question1 _question1 = new question1();
string filename = #"C:\Users\Craigo\Desktop\Quiz_Application\Files\question1.txt";
while (user_level == 1)
{
using (StreamReader sreader = new StreamReader(filename, true))
{
pos += 1;
asked += 1;
_question1.q_No = Convert.ToInt32(sreader.ReadLine());
Console.WriteLine(_question1.q_No);
_question1.Question = sreader.ReadLine();
Console.WriteLine(_question1.Question);
_question1.Choices = sreader.ReadLine();
Console.WriteLine(_question1.Choices);
_question1.Answer = Convert.ToInt32(sreader.ReadLine());
user_input = Convert.ToInt32(Console.ReadLine());
if (user_input == _question1.Answer)
{
score += 1;
user_level += 1;
Console.WriteLine("\nCongratulations, you have scored 1 point and advanced to level 2");
Console.WriteLine("Score = {0}, Questions Asked = {1}", score, asked);
}
}
}
}
What do I do?

the variable "_question1" is not an array:
question1 _question1 = new question1();
So, when you have "_question1[pos]", it won't work.
Your array is "_questions1" (you are missing the 's'):
question1[] _questions1 = new question1[10];
_questions1[pos] should work

The while loop only loops when the variable user_level is 1. Also , you have added that if the user's input is equal to the answer , user_level will increment by 1 which will equal to 2 and hence , the loop will not run again. However , the fact that the program is still looping means that the condition was not met , which tells us that THE USER INPUT IS NOT EQUAL TO THE ANSWER. Hence , the error might be caused by the file. Would you mind showing the contents of the file?

Related

Adding characters to an array list only if it does not already exist

The code below is supposed to read a text file and count all ASCII characters in the file and add up the frequency. Then, it has to write the character, ASCII value and frequency to an output file. The code is below:
class CharacterFrequency
{
char ch;
int frequency;
public char getCharacter()
{
return ch;
}
public void setCharacter(char ch)
{
this.ch = ch;
}
public int getfrequency()
{
return frequency;
}
public void setfrequency(int frequency)
{
this.frequency = frequency;
}
static void Main()
{
Console.WriteLine("Enter the file path");
var InputFileName = Console.ReadLine();
Console.WriteLine("Enter the outputfile name");
var OutputFileName = Console.ReadLine();
StreamWriter streamWriter = new StreamWriter(OutputFileName);
string data = File.ReadAllText(InputFileName);
ArrayList al = new ArrayList();
//create two for loops to traverse through the arraylist and compare
for (int i = 0; i < data.Length; i++)
{
int k = 0;
int f = 0;
for (int j = 0; j < data.Length; j++)
{
if (data[i].Equals(data[j]))
{
f++;
}
}
if (!al.Contains(data[i]))
{
al.Add(data[i] + "(" + (int)data[i] + ")" + f + " ");
}
else
{
k++;
}
//i added the below if statement but it did not fix the issue
foreach (var item in al)
{
streamWriter.WriteLine(item);
}
}
streamWriter.Close();
}
}
The code compiles and runs perfectly fine, but the output file is not correct. It is adding letters that have already been reviewed. I've added an image with the output file showing the incorrect output it is creating. --> enter image description here
How do I check if a character already exists in the array list? The way I am using is not working properly and I have been working on this for a few weeks now to no success. I have tried using the debugger but this issue will not show up there as the code still runs and compiles correctly.
An ArrayList is not well suited for this task, and in fact ArrayLists are not really used anymore. If someone is telling you that you have to do this with an ArrayList
A dictionary would be a much better container for this data. You can use the character as the key, and the count as the value.
Here's one way to do this:
var inputPath = #"c:\temp\temp.txt";
var outputPath = #"c:\temp\results.txt";
var data = new Dictionary<char, int>();
// For each character in the file, add it to the dictionary
// or increment the count if it already exists
foreach (var character in File.ReadAllText(inputPath))
{
if (data.ContainsKey(character)) data[character]++;
else data.Add(character, 1);
}
// Create our results summary
var results = data.ToList()
.Select(item => $"{item.Key} ({(int) item.Key}) {item.Value}");
// Write results to output file
File.WriteAllLines(outputPath, results);
If you have to use an ArrayList (which no one ever uses anymore, but you say have you to for some reason), it would only be useful for storing the results but not keeping track of the counts.
One way to use an ArrayList would be in combination with the Linq extension methods Distinct and Count (first to find all distinct characters, and next to get the count of each one):
foreach (var chr in data.Distinct())
{
al.Add($"{chr} ({(int) chr}) {data.Count(c => c == chr)}");
}
Your algorithm works, but you are duplicating the output as you are writing to the file inside the loop, that is why you are seeing duplicates in the result. If you move the code outside the loop, it should be ok.
foreach (var item in al)
{
streamWriter.WriteLine(item);
}
I would suggest that your algorithm while correct will behave poorly for performance, you are doing too many unnecessary comparisons, perhaps you should read/check more about using dictionaries to store the results.

Index goes out of range when trying to read large excel file [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Hello i am trying to create a file that reads from a excel file 125000 ids and usernames which have to be delimited, create tokens based on that and then creating confirmations links. The problem is that at a certain point in time (after more than 30 000 iterations) the index goes out of range for no concrete reason.
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ExcelDataReader;
using Excel = Microsoft.Office.Interop.Excel;
namespace CoRegApp
{
public class Excel_Creation
{
static string[] tokens;
string emailConfirmationLink;
public List<string> EmailsList = new List<string>();
public List<string> userList = new List<string>();
//Create a variable of the token date
public Excel_Creation() { }
public void readExcel()
{
string filepath = "batch2.xlsx";
var tokenDate = DateTime.Now.AddDays(4).Date;
using (FileStream stream = File.Open(filepath, FileMode.Open, FileAccess.Read))
{
using (IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream))
{
DataSet result = excelReader.AsDataSet();
DataTable firstTable = result.Tables[0];
//StringBuilder sb = new StringBuilder();
foreach (DataRow dr in firstTable.Rows)
{
object[] arr = dr.ItemArray;
for (int i = 0; i < arr.Length; i++)
{
string input = ((Convert.ToString(arr[i])));
if (!string.IsNullOrWhiteSpace(input))
{
tokens = input.Split(';');
for (i = 0; i < 1; i++)
{
string token = EncryptionHelper.CreateToken(tokens[0], tokens[1], tokenDate);
emailConfirmationLink = "https://blablaconfirmation/Validate?token=" + token + "&blablavalidation2";
EmailsList.Add(emailConfirmationLink);
userList.Add((Convert.ToString(arr[i])));
Console.WriteLine(emailConfirmationLink);
}
}
//tokens =().Split(';'));
}
}
excelReader.Close();
}
}
}
public void MapToExcel()
{
//start excel
Excel.Application excapp = new Microsoft.Office.Interop.Excel.Application();
//if you want to make excel visible
excapp.Visible = true;
//create a blank workbook
var workbook = excapp.Workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet);
//Not done yet. You have to work on a specific sheet - note the cast
//You may not have any sheets at all. Then you have to add one with NsExcel.Worksheet.Add()
var sheet = (Excel.Worksheet)workbook.Sheets[1]; //indexing starts from 1
//now the list
string cellName;
int counter = 1;
foreach (string item in EmailsList)
{
cellName = "B" + counter.ToString();
var range = sheet.get_Range(cellName, cellName);
range.Value2 = item.ToString();
++counter;
}
string cellName2;
int counterB = 1;
foreach (string item in userList)
{
cellName2 = "A" + counterB.ToString();
var range = sheet.get_Range(cellName2, cellName2);
range.Value2 = item.ToString();
++counterB;
}
}//end of mapping method
}
}
You have reused the looping variable "i" within the loop of "i":
for (int i = 0; i < arr.Length; i++)
{
...
for (i = 0; i < 1; i++)
The clue is that you didn't have to declare the variable for the inner loop. You should always expect to declare your looping variable in the for (or foreach); or you're probably doing something wrong.
In this case, what will happen, is that it will enter the outer loop, set "i" to zero, check that i is less than arr.Length; do some other stuff, and if the conditions are right, it will enter the inner loop (which re-sets "i" to zero, checks it is less than 1, does the contents of the inner loop, increments i (because of the inner loop), drops out of that loop, reaches the end of the outer loop, increments i again (so now it's 2), and checks against arr.Length before possibly going round again.
That inner loop is effectively pointless because it will always do it once and only once, so I'd suggest removing that loop, and fixing the references to "i" within it to either be 0, or to stay as "i"; depending on what your intent was (because it's ambiguous which "i" you were trying to refer to).
If I can suggest that you always give your variables names, you may find that it not only helps prevent you doing this; but it will make your code more readable.
If it helps, you can think of a for-loop as being like a while loop that is coded like this...
int i = 0;
while(i < arr.Length)
{
...
i++;
}
But you have tinkered with "i" in the "..." part.
EDIT: additional:
tokens = input.Split(';');
...
string token = EncryptionHelper.CreateToken(tokens[0], tokens[1], tokenDate);
but there is no check of how many items are in tokens before using the indexers.
Thanks for your help.
Actually the issue was kind of dumb. Even if my array will always be resetted to contain only two items of index[0] and [1]. hardcoding it to access those values seems to make the loop go out of bound at some point in time. Don't really know. Thus simply replacing the
string token = EncryptionHelper.CreateToken(tokens[0], tokens[1], tokenDate);
with
int counter1 = counter;
counter1--;
string token = EncryptionHelper.CreateToken(tokens[counter1], tokens[counter], tokenDate);
solved the issue

How do I read in a text file with a loop, line by line [duplicate]

This question already has answers here:
What's the fastest way to read a text file line-by-line?
(9 answers)
Closed 5 years ago.
So I am just starting out C# with little to no knowledge, so this is more for learning for me than practical use. Therefore what I really would like to know is how I can get my code to work my way, even if there is a much simpler/quicker/smarter solution.
So what I wanna do is create a string array, and using a loop read in each line from a text file into a corresponding element of the array. That's what I tried to do here, and I would love to hear what solutions you have for this.
{
class Program
{
static void Main(string[] args)
{
StreamReader ki = new StreamReader("kiserlet.txt");
string[] a = new string[15];
Console.ReadLine();
int y = 0;
int n = 0;
for (int i = 0; i > 15; i++)
{
a[n] = Convert.ToString(ki.ReadLine());
n++;
}
for (int x = 0;x > 15;x++)
{
Console.WriteLine(a[y]);
y++;
}
Console.ReadLine();
ki.Close();
}
}
}
You can read each line of the file into an array, then iterate through it.
class Program
{
static void Main(string[] args)
{
// this will read all lines from within the File
// and automatically put them into an array
//
var linesRead = File.ReadLines("kiserlet.txt");
// iterate through each element within the array and
// print it out
//
foreach (var lineRead in linesRead)
{
Console.WriteLine(lineRead);
}
}
}

c# how to store values from a file in an array [duplicate]

This question already has answers here:
C# parsing a text file and storing the values in an array
(3 answers)
Closed 5 years ago.
I am trying to store values in an array from reading from a file. I have the reading from a file part but I can't get it to store in an array because it gives me an error "Value cannot be null" because after the loop the value of my variable becomes null and the array cannot be null. Here's what I have. And I realize that the for loop probably isn't in the correct spot so any help with where to put it would be great.
Program p = new Program();
int MAX = 50;
int[] grades = new int[MAX];
string environment = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) + "\\";
string path = environment + "grades.txt";
StreamReader myFile = new StreamReader(path);
string input;
int count = 0;
do
{
input = myFile.ReadLine();
if (input != null)
{
WriteLine(input);
count++;
}
} while (input != null);
for (int i = 0; i < count; i++)
{
grades[i] = int.Parse(input);
}
You start the for loop just after exiting from the while loop. And the condition to exit from the while loop is true when input is null. Of course this is not well accepted by Int.Parse.
Instead you can use a single loop, taking in consideration that you don't want to loop more than 50 times otherwise you exceed the array dimensions
int count = 0;
while((input = myFile.ReadLine()) != null && count < 50)
{
WriteLine(input);
grades[count] = int.Parse(input);
count++;
}
However you can have a more flexible way to handle your input if you use a List<int> instead of an array of integers. In this way you don't have to check for the number of lines present in your file
List<int> grades = new List<int>();
while((input = myFile.ReadLine()) != null)
grades.Add(int.Parse(input));
if we want to get really condensed
var grades = File.ReadAllLines(path).Select(l=>Int.Parse(l)).ToArray();
Utilize the Path.Combine() to help you in concatenating paths.
string environment = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
String fullPath = Path.Combine(environment, "grades.txt");
int[] grades = File.ReadAllLines(fullPath).Select(p => int.Parse(p)).ToArray<int>();
Console.WriteLine(grades);
Refer to https://www.dotnetperls.com/file-readalllines on how to use File.ReadAllLines() its very handy.
I'm using LINQ here, which sometimes simplifies things. Even though it looks a bit intimidating now. We read all lines, the result of that is then parsed by selecting each one and converting it to an integer then outputting an array of integers and saving that to grades.
Program p = new Program();
int MAX = 50;
int[] grades = new int[MAX];
string environment = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) + "\\";
string path = environment + "grades.txt";
using (StreamReader myFile = new StreamReader(path))
{
string input;
int count = 0;
while((!myFile.EndOfStream) && (count < MAX))
{
input = myFile.ReadLine();
if (!String.IsNullOrWhiteSpace(input))
{
WriteLine(input);
grades[count] = int.Parse(input);
count++;
}
}
}
You should definitely use the "using" pattern around your stream object. Got rid of the for-loop for you while maintaining mostly your code and style. Your issue was that you weren't using the input value before moving on to the next line. You only ever had the last value in your original code.

System.FormatException has been thrown input string was not in a correct format [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FajlbolOlvasas
{
class Program
{
struct Student
{
public string name;
public double avarage;
}
static void Main(string[] args)
{
StreamReader f = new StreamReader("joci.txt");
Student[] students = new Student[Convert.ToInt32(f.ReadLine())];
for (int i = 0; i < tanulok.Length && !f.EndOfStream; i++)
{
students[i].name = f.ReadLine();
students[i].avarage = Convert.ToDouble(f.ReadLine());
Console.WriteLine(students[i].name + " - " + students[i].avarage);
}
f.Close();
Console.ReadKey();
}
}
}
The txt file was saved at bin/Release
the console appears but that is just an empty one
it says System.FormatException has been thrown input string was not in a correct format
the content of the txt file is :
Tomi
4
Lee
3
Bob
5
Okay so besides of the main problem which is FormatException i see few others.
First one is that you are processing "unknown" file contents into an array instead of list. This can be skipped if you know how the file is structured using example below:
string[] fileContents = File.ReadAllLines("joci.txt");
Student[] students = new Student[fileContents.Lengthe / 2]; // because 2 lines describes student
But better solution is to do this using List<> instead of array :
List<Student> students = new List<Student>();
Next thing that is totally wrong is that you're assuming that you know the file contents. You should always leave some margin for errors, and first try to convert type instead of demanding type conversion:
string line = f.ReadLine();
int convertedLine = 0;
if ( int.TryParse( line, out convertedLine ) ) {
// now convertedLine is succesfully converted into integer type.
}
So making the final conclusion :
ALWAYS leave some margin for errors.
The good ( but still not the best ) solution for your problem would be :
string[] fileContents = File.ReadAllLines("joci.txt");
Student[] students = new Student[fileContents.Length / 2];
for (int i = 0, j = 0; i < fileContents.Length; i += 2, j++)
{
string name = fileContents[i];
int av = 0;
if ( int.TryParse( fileContents[i + 1], out av ) {
students[j] = new Student { name = name, average = av };
Console.WriteLine(students[j].name + " - " + students[j].avarage);
}
}
Console.ReadKey();

Categories