vb.net access the streamreader.readline which is currently looping - vb.net

In C#, it seems the following method works which will allow you to
call Streamreader.readline() and then access that very same line in the next loop.
string line;
double score = 0;
count = 0;
while ((line = sr.ReadLine()) != null)
{
score += double.Parse (line);
count++;
}
averageScore = (double)inValue / count;
This does not work in vb.net though, even with all the converters which I tried.
this one completely bombs out and throws "page not found"
http://converter.telerik.com/
this one:
http://www.developerfusion.com/tools/convert/csharp-to-vb/?batchId=3356dd81-818a-43d1-8c23-be584e40d15e
results in :
Dim line As String
Dim score As Double = 0
count = 0
While (InlineAssignHelper(line, sr.ReadLine())) IsNot Nothing
score += Double.Parse(line)
count += 1
End While
averageScore = CDbl(inValue) / count
where InlineAssignHelper is something I dont have.

If you have the filename, instead of just a stream, you can use System.IO.File.ReadLines for the neatest way:
Dim score As Double = 0
count = 0
For Each line In File.ReadLines(filename)
score += Double.Parse(sr.ReadLine())
count += 1
Next
averageScore = CDbl(inValue) / count
Or use LINQ:
Dim averageScore = File.ReadLines(filename).Average(AddressOf Double.Parse)

Use a Do-Loop with an exit statement, like this:
Do
Dim line = sr.ReadLine()
If line Is Nothing Then Exit Do
score += Double.Parse(line)
count += 1
Loop
Do note the advantage of doing it this way over the accepted answer, it is very lean on memory usage and doesn't require the entire file to fit in memory.

Related

Progress bar with VB.NET Console Application

I've written a parsing utility as a Console Application and have it working pretty smoothly. The utility reads delimited files and based on a user value as a command line arguments splits the record to one of 2 files (good records or bad records).
Looking to do a progress bar or status indicator to show work performed or remaining work while parsing. I could easily write a <.> across the screen within the loop but would like to give a %.
Thanks!
Here is an example of how to calculate the percentage complete and output it in a progress counter:
Option Strict On
Option Explicit On
Imports System.IO
Module Module1
Sub Main()
Dim filePath As String = "C:\StackOverflow\tabSeperatedFile.txt"
Dim FileContents As String()
Console.WriteLine("Reading file contents")
Using fleStream As StreamReader = New StreamReader(IO.File.Open(filePath, FileMode.Open, FileAccess.Read))
FileContents = fleStream.ReadToEnd.Split(CChar(vbTab))
End Using
Console.WriteLine("Sorting Entries")
Dim TotalWork As Decimal = CDec(FileContents.Count)
Dim currentLine As Decimal = 0D
For Each entry As String In FileContents
'Do something with the file contents
currentLine += 1D
Dim progress = CDec((currentLine / TotalWork) * 100)
Console.SetCursorPosition(0I, Console.CursorTop)
Console.Write(progress.ToString("00.00") & " %")
Next
Console.WriteLine()
Console.WriteLine("Finished.")
Console.ReadLine()
End Sub
End Module
1rst you have to know how many lines you will expect.
In your loop calculate "intLineCount / 100 * intCurrentLine"
int totalLines = 0 // "GetTotalLines"
int currentLine = 0;
foreach (line in Lines)
{
/// YOUR OPERATION
currentLine ++;
int progress = totalLines / 100 * currentLine;
///print out the result with the suggested method...
///!Caution: if there are many updates consider to update the output only if the value has changed or just every n loop by using the MOD operator or any other useful approach ;)
}
and print the result on the same posititon in your loop by using the SetCursor method
MSDN Console.SetCursorPosition
VB.NET:
Dim totalLines as Integer = 0
Dim currentLine as integer = 0
For Each line as string in Lines
' Your operation
currentLine += 1I
Dim Progress as integer = (currentLine / totalLines) * 100
' print out the result with the suggested method...
' !Caution: if there are many updates consider to update the output only if the value has changed or just every n loop by using the MOD operator or any other useful approach
Next
Well The easiest way is to update the progressBar variable often,
Ex: if your code consist of around 100 lines or may be 100 functionality
after each function or certain lines of code update progressbar variable with percentage :)

How to not generate a stack overflow when a sub procedure calls itself?

This code generates a stack overflow. I'm aware it is caused by the procedure calling itself.
What can I do to avoid the stack overflow? Recalling the sub procedure and generating a new random number is the easiest thing to do, however it generates the overflow. The randomly generated number picks a random inventory item, then the if statement matches that number (random inventory item) with the quantity of that item from the deck inventory to make sure it isn't less than 1. If the inventory of that item is 0, the else plays and restarts the procedure, generating a new random number and doing the process all over again. In another procedure I have a function that if the deck's inventory becomes completely empty, then the discard pile replenishes the deck, making the discard pile empty, so there should never be a case where all randomly generated numbers can be associated item with a inventory of 0.
I wonder if I could somehow force the random number generator
Number = (DeckGroup(Rnd.Next(0, DeckGroup.Count)).ID)
not to generate numbers to inventory items DeckGroup(Number).QuantityInteger that are zero. By doing so I wouldn't even need to recall the function.
The random number is generated by a different branch in the same structure group.
Private Sub PlayElse()
Dim CardCheckBoxArray() As CheckBox = {CardCheckBox1, CardCheckBox2, CardCheckBox3, CardCheckBox4, CardCheckBox5}
'Reset Number Generator
Number = (DeckGroup(Rnd.Next(0, DeckGroup.Count)).ID)
Dim PlayerQuantitySubtractionInteger As Integer
For PlayerQuantitySubtractionInteger = ChecksDynamicA To ChecksDynamicB
If CardCheckBoxArray(TextBoxInteger).Checked = True And DeckGroup(Number).QuantityInteger > 0 Then
DeckGroup(Number).QuantityInteger -= 1
'Select the Player depending value of T
Select Case T
Case 0
Player1HandGroup(Number).QuantityInteger += 1
Case 1
Player1HandGroup(Number).QuantityInteger2 += 1
Case 2
Player1HandGroup(Number).QuantityInteger3 += 1
Case 3
Player1HandGroup(Number).QuantityInteger4 += 1
Case 4
Player1HandGroup(Number).QuantityInteger5 += 1
End Select
CardTypeArray(PlayerQuantitySubtractionInteger) = Player1HandGroup(Number).CardType
CardCheckBoxArray(TextBoxInteger).Text = Player1HandGroup(Number).CardNameString
NumberArray(PlayerQuantitySubtractionInteger) = Number
Else
If CardCheckBoxArray(TextBoxInteger).Checked = True And DeckGroup(Number).QuantityInteger < 0 Then
Call PlayElse()
End If
End If
Next PlayerQuantitySubtractionInteger
End Sub
You could use LINQ to weed out all the objects you never want to get first and then use the collection returned by the linq instead of your original collection.
Something like:
Private Sub PlayElse()
Dim CardCheckBoxArray() As CheckBox = {CardCheckBox1, CardCheckBox2, CardCheckBox3, CardCheckBox4, CardCheckBox5}
'Reset Number Generator
Dim temp As IEnumerable(Of LunchMoneyGame.LunchMoneyMainForm.Group) = From r In DeckGroup Where r.QuantityInteger > 0 Select r
If temp IsNot Nothing AndAlso temp.Any Then
Number = (temp(Rnd.Next(0, temp.Count)).ID)
' ** Edit **: This will ensure that you only got 1 object back from the LINQ which can tell you whether or not you have bad data. You *can* exclude this check but its good practice to include it.
Dim obj As LunchMoneyGame.LunchMoneyMainForm.Group = Nothing
Dim t = From r In temp Where r.ID = Number Select r
If t IsNot Nothing AndAlso t.Count = 1 Then
obj = t(0)
End If
If obj IsNot Nothing Then
Dim PlayerQuantitySubtractionInteger As Integer
For PlayerQuantitySubtractionInteger = ChecksDynamicA To ChecksDynamicB
' ** Edit **
obj.QuantityInteger -= 1
'Select the Player depending value of T
Select Case T
Case 0
Player1HandGroup(Number).QuantityInteger += 1
Case 1
Player1HandGroup(Number).QuantityInteger2 += 1
Case 2
Player1HandGroup(Number).QuantityInteger3 += 1
Case 3
Player1HandGroup(Number).QuantityInteger4 += 1
Case 4
Player1HandGroup(Number).QuantityInteger5 += 1
End Select
CardTypeArray(PlayerQuantitySubtractionInteger) = Player1HandGroup(Number).CardType
CardCheckBoxArray(TextBoxInteger).Text = Player1HandGroup(Number).CardNameString
NumberArray(PlayerQuantitySubtractionInteger) = Number
Next PlayerQuantitySubtractionInteger
End If
End If
End Sub
Pass through the list and determine only those that are valid. Then randomly pull from that set. Here is a simple version of it. You could use LINQ as well, but this should be clear enough:
Dim validDeckGroupsIndexes As New List(Of Integer)
For ndx As Integer = 0 to DeckGroup.Count - 1
If DeckGroup(ndx).QuantityInteger > 0 Then
validDeckGroupsIndexes .Add(ndx)
End If
Next ndx
Then use this:
Dim deckGroupNdx As Integer = Rnd.Next(0, validDeckGroupsIndexes.Count)
Number = DeckGroup(deckGroupNdx).ID

How do I use loops in VB.NET?

EDIT:
I have a ItemList : Dim ItemList As New List(Of String)
I wanna append each element from itemlist to a new list for 10 times each, then to start over again.
How can I make a loop for each element while there are still elements in the list (10 times each)?
I tried this but it's not working. it's too complicated for me cause I'm a newbie
Private crt As Integer = 0
Private limit As Integer = 0
Private Function getline() As String
Dim line As String = ""
SyncLock addlines
Do While limit < 10
line = ItemList(crt)
limit += 1
Loop
limit = 0
crt += 1
End SyncLock
addlines.AppendText(Environment.NewLine & line & " limit:" & limit & " crt:" & crt)
'Return line
End Function
thanks
I have also tried this:
For Each I As Item In Items
If I = x Then Continue For
' Do something
Next
but I didn't know where to add the 10 times limit and also the current item number(crt)
As best I can make out of that mess of a question, you seem to want to append each line in ItemList (whatever that object is) 10 times.
This should do the trick.
Dim limit as integer=10
For each line as string in ItemList
For lineNum as integer = 1 to limit
addlines.AppendText(string.format("{0}{1} Limit: {2} CRT:{3}", Environment.NewLine, line, limit, lineNum ))
Next lineNum
Next line
Update: Updated answer for explanation in comments about what CRT was.

How can I search a listbox and save all the results in another listbox?

for now, i am using this code but it doesnt give me what i want..
for example i want to list all the items with the string "1"
Dim x, count As Integer
x = ListBox1.Items.Count
count = 0
Do While count < x
If ListBox1.SelectedIndex = ListBox1.FindString("1") Then
ListBox2.Items.Add(ListBox1.Items(count))
End If
count = count + 1
Loop
Try this.
foreach (string s in listBox1.Items)
{
if(s.contains("1"))
listbox2.add(s);
}

Most efficient way to jump through a file and read lines?

I want to use a FileStream and seek from the beginning of the file while moving forward in the file .01% of the file size at a time.
So I want to seek to a position in the file, read the entire line, if it matches my criteria I am done. If not, I seek ahead another .01.
C# is OK but VB.NET preferred.
I used to do it something like this in VB6...
FileOpen(1, CurrentFullPath, OpenMode.Input, OpenAccess.Read, OpenShare.Shared)
Dim FileLength As Long = LOF(1)
For x As Single = 0.99 To 0 Step -0.01
Seek(1, CInt(FileLength * x))
Dim S As String = LineInput(1)
S = LineInput(1)
filePosition = Seek(1)
If filePosition < 50000 Then
filePosition = 1
Exit For
End If
V = Split(S, ",")
Dim MessageTime As Date = CDate(V(3) & " " & Mid$(V(4), 1, 8))
Dim Diff As Integer = DateDiff(DateInterval.Minute, MessageTime, CDate(RequestedStartTime))
If Diff >= 2 Then
Exit For
End If
Next
But I don't want to use FileOpen, I want to use a FileStream.
Any help is greatly appreciated!
This is a more or less direct conversion of your code, where we use FileStream.Position to specify where in the file to read:
Using streamReader As System.IO.StreamReader = System.IO.File.OpenText(CurrentFullPath)
For x As Single = 0.99 To 0 Step -0.01
streamReader.BaseStream.Position = CLng(streamReader.BaseStream.Length * x)
Dim S As String = streamReader.ReadLine()
'... etc.
Next
End Using
what bout something like this (C# version):
using (var file = System.IO.File.OpenText(filename))
{
while (!file.EndOfStream)
{
string line = file.ReadLine();
//do your logic here
//Logical test - if true, then break
}
}
EDIT: VB version here (warning - from a C# dev!)
Using file as FileStream = File.OpenText(filename)
while Not file.EndOfStream
Dim line as string = file.ReadLine()
''//Test to break
''//exit while if condition met
End While
End Using
I normally prefer vb.net, but C#'s iterator blocks are slowly winning me over:
public static IEnumerable<string> SkimFile(string FileName)
{
long delta = new FileInfo(FileName).Length / 100;
long position = 0;
using (StreamReader sr = new StreamReader(FileName))
{
while (position < 100)
{
sr.BaseStream.Seek(position * delta, SeekOrigin.Begin);
yield return sr.ReadLine();
position++;
}
}
}
Put it in a class library project and use it from vb like this:
Dim isMatch as Boolean = False
For Each s As String in SkimFile("FileName.txt")
If (RequestedDate - CDate(s.SubString(3,11))).Minutes > 2 Then
isMatch = True
Exit For
End If
Next s
(I took some liberties with you criteria (assumed fixed-width values rather than delimited) to make the example easier)
There's an example on MSDN.
Edit in response to comment:
I must admit I'm a bit confused, as you seemed insistant on using a buffered FileStream, but want to read a file a line at a time? You can do that quite simply using a StreamReader. I don't know VB, but in C# it would be something like this:
using (StreamReader sr = File.OpenText(pathToFile))
{
string line = String.Empty;
while ((line = sr.ReadLine()) != null)
{
// process line
}
}
See http://msdn.microsoft.com/en-us/library/system.io.file.aspx.