Recursive For Each loop doesnt seem to recurse properly - vb.net

For some reason, it seems that the outer block doesn't seem to update recursively, as I expected it to. I want the loops to add all directories within "C:\Users\Drise"to the array internaldirs(). Any advice on the correct way to do this, as it seems I'm doing it improperly?
Static internaldirs() As String
internaldirs.add("C:\Users\Drise")
For Each internaldir As String In internaldirs
For Each direc As String In Directory.GetDirectories(internaldir)
internaldirs.Add(direc)
Next
Next
Solution:
Sub recursivedirs()
Static internaldirs As New List(Of String)
Try
If internaldirs(0) = "C:\Users\Drise" Then
Call AddDirToList(internaldirs, internaldirs(0))
End If
Catch
internaldirs.Add("C:\Users\Drise")
Call AddDirToList(internaldirs, internaldirs(0))
End Try
End Sub
Private Sub AddDirToList(ByRef dirs As List(Of String), ByVal currentDir As String)
dirs.Add(currentDir)
Try
For Each subDir As String In Directory.GetDirectories(currentDir)
AddDirToList(dirs, subDir)
Next
Catch
End Try

Short answer is: you can't modify a collection (internaldirs) that you're iterating over.
Longer answer: Looks like you're trying to build a string array listing the folder in the directory tree. A better way would be to use a List and a recursive function.
Static dirs As List(Of String)
dirs = New List(Of String)
AddDirToList(dirs, "C:\Users\Drise")
Private Sub AddDirToList (dirs as List(Of String), currentDir as String)
dirs.Add(currentDir)
For Each subDir As String In Directory.GetDirectories(currentDir)
AddDirToList(dirs, currentDir)
Next
End Sub
Please excuse any syntax issues. I'm more of a C# guy.

As Andrew Cooper said, you can't modify a collection being used in a For Each loop.
You can do it with an index counter.
Dim internaldir As List(Of String)
internaldir.Add("C:\Users\Drise")
Dim i As Integer = 0
Do Until i >= internaldir.Count
Dim internaldir As String = internaldirs(i)
For Each currentdir As String In Directory.GetDirectories(internaldir)
internaldirs.Add(currentdir)
Next
i += 1
Loop
' If you want an array as output, use:
Dim array As String() = internaldirs.ToArray()

Related

VB.net Apply function to items in a list

I have a list of string containing full file paths and I'd like to apply a function to each path in that list and get the result in the same or a new list.
Dim Remove As New List(Of String)
Remove.Add("C:\_Vault\Designs\Jobs\Customer\Job23\Assemblies\045-0201.iam")
Remove.Add("C:\_Vault\Designs\Jobs\Customer\Job23\Parts\212-D017.ipt")
Remove.Add("C:\_Vault\Designs\Jobs\Customer\Job23\Parts\211-W01.iam")
Function FileName(spth As String) As String
'Returns filename with extension from full path
Return System.IO.Path.GetFileName(spth)
End Function
The end result I'd like is for the list Remove to contain the following. I know I could use a loop to do this but I've been learning about lambda expressions lately and feel there should be a simple solution to this.
{"045-0201.iam", "212-D017.ipt", "211-W01.iam"}
Try this
Dim Remove As New List(Of String)
Remove.Add("C:\_Vault\Designs\Jobs\Customer\Job23\Assemblies\045-0201.iam")
Remove.Add("C:\_Vault\Designs\Jobs\Customer\Job23\Parts\212-D017.ipt")
Remove.Add("C:\_Vault\Designs\Jobs\Customer\Job23\Parts\211-W01.iam")
Remove = Remove.Select(Function(s)
Return IO.Path.GetFileName(s)
End Function).ToList
Calling Select and ToList on the existing List is most likely fine and what most people would do. It's worth being aware, though, that that will not modify the existing collection but rather return a new one. If you only have the one reference to that list then that's not a big deal but other references to the existing list will not see the change, e.g.
Dim fileNames As New List(Of String) From {"C:\Folder\File1.ext",
"C:\Folder\File2.ext",
"C:\Folder\File3.ext"}
Dim temp = fileNames
fileNames = fileNames.Select(Function(s) Path.GetFileName(s)).ToList()
For Each fileName In fileNames
Console.WriteLine(fileName)
Next
For Each fileName In temp
Console.WriteLine(fileName)
Next
If you run that then you'll see that the first loop displays just the files names but the second loop displays the full paths, because it still refers to the original list.
If that's a problem, there is another way to do this without an explicit loop:
Dim fileNames As New List(Of String) From {"C:\Folder\File1.ext",
"C:\Folder\File2.ext",
"C:\Folder\File3.ext"}
Dim temp = fileNames
Array.ForEach(Enumerable.Range(0, fileNames.Count).ToArray(),
Sub(i) fileNames(i) = Path.GetFileName(fileNames(i)))
For Each fileName In fileNames
Console.WriteLine(fileName)
Next
For Each fileName In temp
Console.WriteLine(fileName)
Next
If you run that then you'll see that both loops display just the file names because there's only one list.
That said, if the first code posed a problem because of multiple references to the list, I'd just use a loop.
I know you stated that you'd want something other than a loop, but there really is no needfor anything fancy here. By the way, writing Remove.Add sounds like a riddle.
Sub Main()
Dim Remove As New List(Of String)
Remove.Add("C:\_Vault\Designs\Jobs\Customer\Job23\Assemblies\045-0201.iam")
Remove.Add("C:\_Vault\Designs\Jobs\Customer\Job23\Parts\212-D017.ipt")
Remove.Add("C:\_Vault\Designs\Jobs\Customer\Job23\Parts\211-W01.iam")
Console.WriteLine("Before execution")
For Each s As String In Remove
Console.WriteLine(s)
Next
For i As Integer = 0 To Remove.Count - 1
Remove(i) = MyFunction(Remove(i))
Next
Console.WriteLine("After execution")
For Each s As String In Remove
Console.WriteLine(s)
Next
Console.ReadLine()
End Sub
Private Function MyFunction(path As String) As String
Return IO.Path.GetFileName(path)
End Function
This outputs:

Using TextBox as Path Like OpenFileDialog

I hope someone can help me.
In short, I have this little code
I can't replace "Path from my pc" with a string/textbox in any way
The intention would be this:
enumerator = SpotifyBox.Text.Split.GetEnumerator
It doesn't give me errors, but it doesn't work as it should once the button starts
Dim enumerator As List(Of String).Enumerator = New List(Of String).Enumerator()
Dim class70 As Action(Of String())
ThreadPool.SetMinThreads(40, 40)
Dim strArrays As List(Of String()) = New List(Of String())()
Try
Try
enumerator = File.ReadLines(Path from pc).ToList().GetEnumerator()
While enumerator.MoveNext()
Dim current As String = enumerator.Current
If (If(Not current.Contains(":"), True, String.IsNullOrEmpty(current))) Then
Continue While
End If
strArrays.Add(current.Split(New Char() {":"c}))
End While
Finally
DirectCast(enumerator, IDisposable).Dispose()
End Try
int_5 = strArrays.Count
Catch exception1 As System.Exception
End Try
That is some crazy code and the question you're asking is not the question you need an answer to. Based on what you have posted, it seems that you have a file path in a TextBox named SpotifyBox and you want to read the lines from that file with some processing. In that case, get rid of all that craziness and do this:
Dim filePath = SpotifyBox.Text
Dim records As New List(Of String())
For Each line In File.ReadLines(filePath)
If line.Contains(":") Then
records.Add(line.Split(":"c))
End If
Next
That's it, that's all. You pretty much never need to create an enumerator directly. Just use a For Each loop.

Contents of List(Of String) are not saved

I am attempting to parse paragraphs such as the following...
Group 1. Does this or does that. Or Sometimes this. Or that.
Group 2. I do lots of things. But not this. Or that.
Group 3. I do this. I do that. Sometimes this. Sometimes that.
The "Group 1-3" are the org Names, and each following sentence separated by a period is a function.
Code:
Public Sub parseParagraphs(paragraphList As List(Of String))
Dim listOfOrgs As New List(Of EAB_Org)
Dim listOfFuntions As New List(Of String)
Dim orgName As String
For Each item In paragraphList
listOfFuntions.Clear()
Dim words As String() = item.Split(New Char() {"."c}) 'Splits on periods
orgName = words(0) 'Sets the orgName
For index As Integer = 1 To words.Count - 1 'rest of items in list are functions performed
listOfFuntions.Add(words(index))
Next
Dim anOrg As New EAB_Org(orgName, listOfFuntions)
listOfOrgs.Add(anOrg)
Next
End Sub
EAB Class:
Public Class EAB_Org
Dim orgName As String
Dim listOfTasks As List(Of String)
Public Sub New(theOrgName As String, theListOfTasks As List(Of String))
orgName = theOrgName
listOfTasks = theListOfTasks
End Sub
Public Function getOrgName()
Return orgName
End Function
Public Function getListOfTasks()
Return listOfTasks
End Function
End Class
For some reason, when I print out the contents of listOfOrgs, all the org names are correct, but the functions are all of the same and always the last set of functions read in.
Code I use to print:
Public Sub writeExcel(listOfOrgs As List(Of EAB_Org))
For Each anItem In listOfOrgs
Console.WriteLine(anItem.getOrgName)
For Each anotherItem In anItem.getListOfTasks
Console.WriteLine(anotherItem)
Next
Next
End Sub
Output Looks Like:
Group 1
I do this. I do that. Sometimes this. Sometimes that.
Group 2
I do this. I do that. Sometimes this. Sometimes that.
Group 3
I do this. I do that. Sometimes this. Sometimes that.
The problem is that in the constructor for EAB_Org, theListOfTasks is just a pointer to listOfFuntions (which you keep modifying) in the parseParagraphs Sub. In the constructor, you will need to create a new List(Of String) and copy the values from theListOfTasks into it.
Change the constructor to the following:
Public Sub New(theOrgName As String, theListOfTasks As List(Of String))
orgName = theOrgName
listOfTasks = New List(Of String)
For Each item As String In theListOfTasks
listOfTasks.Add(item)
Next
End Sub

How to search a folder with its subfolders and save the results to an array VB.NET

I am trying to execute a search on a folder and get an array of every result back. I found this code but it doesn't go into subfolders:
Dim Results As New List(Of String)
For Each strFileName As String In IO.Directory.GetFiles("pathToSearch")
If strFileName.Contains("searchTerm") Then
Results.Add(strFileName)
End If
Next
How can I do exactly this, but also look into the subfolders?
I'm not very knowledgeable about the search options in VB.NET yet, so I apologize in advance if this seems stupid. I have tried searching online but haven't found anything. I can't have a single string, it needs to be an array (this needs to be interpreted by the machine later in the program)
Thanks for any help
No recursion required. There is already an overload for this. You just need to call it with appropriate search option.
e.g. To list all txt files in the directory as well as the subdirectories you can do:
Dim foundFiles() As String = System.IO.Directory.GetFiles("path/to/dir", "*.txt", System.IO.SearchOption.AllDirectories)
In order to get the subfolders you might try some recursive function
Unless there's a file system search API with which I'm unfamiliar, this is going to involve a recursive method to perform the searching into sub-directories.
Helpfully, Microsoft even has a complete example of something very similar available. In VB it might look something like this (my VB is very rusty and this is free-hand code, by the way...):
Function FindFiles(ByVal dir As String, ByVal searchTerm As String) As List(Of String)
Dim Results As New List(Of String)
' search files in this directory
For Each strFileName As String In IO.Directory.GetFiles(dir)
If strFileName.Contains(searchTerm) Then
Results.Add(strFileName)
End If
Next
' recurse into child directories
For Each strDirectoryName As String In IO.Directory.GetDirectories(dir)
Results = Results.AddRange(FindFiles(strDirectoryName, searchTerm)
Next
Return Results
End Function
Make a recursive function that keeps calling itself until all subdirectories are checked:
Private Function GetAllFileNamesFromDirectory(ByVal strPath As String, ByVal strSearchTerm As String) As List(Of String)
Dim lstFileNames As New List(Of String)
Dim lstSubDirectories As List(Of String) = IO.Directory.GetDirectories(strPath).ToList()
Dim lstFilesToAdd As List(Of String) = IO.Directory.GetFiles(strPath).ToList()
For Each strFileToAdd As String In lstFilesToAdd
If strFileToAdd.Contains(strSearchTerm) Then
'Additional logic would be required to filter out the directory name.
lstFileNames.Add(strFileToAdd)
End If
Next
If lstSubDirectories.Count > 0 Then
lstSubDirectories.ForEach(Sub(strDirectoryPath As String)
Dim lstSubDirectoryFilesToAdd As List(Of String) = GetAllFileNamesFromDirectory(strDirectoryPath, strSearchTerm)
If lstSubDirectoryFilesToAdd.Count > 0 Then
lstFileNames.AddRange(lstSubDirectoryFilesToAdd)
End If
End Sub)
End If
Return lstFileNames
End Function

List all folders that are in any 3rd subdirectory from current

I would need to make an array list, displaying all folders that are in the 3rd subfolder from the current one.
Folder1/sub1folder/sub2folder/sub3folder
It has to be recursive. what I need is an array of strings that contains all the strings like above.
I do know how to look recursively into folders, but I do not know how to limit the search to the 3rd subfolder.
Thanks!
Here's my stab at it. I tested it and it works for me:
Dim resultList as List(Of String) = DirectorySearch(baseDirectoryPath, 0)
Function DirectorySearch(directoryPath As String, level As Integer) As List(Of String)
level += 1
Dim directories As String() = IO.Directory.GetDirectories(directoryPath)
Dim resultList As New List(Of String)
If level = 3 Then
For Each subDirectoryPath In directories
Dim result As String = GetFinalResult(subDirectoryPath)
resultList.Add(result)
Next
Else
For Each subDirectoryPath In directories
Dim partialResultList As List(Of String) = DirectorySearch(subDirectoryPath, level)
resultList.AddRange(partialResultList)
Next
End If
Return resultList
End Function
Private Function GetFinalResult(directoryPath As String) As String
Dim directoryInfo As New IO.DirectoryInfo(directoryPath)
Return String.Format("{0}/{1}/{2}/{3}",
directoryInfo.Parent.Parent.Parent.Name,
directoryInfo.Parent.Parent.Name,
directoryInfo.Parent.Name,
directoryInfo.Name)
End Function
If you had a recursive function which began at the current folder:
Public Function recurse(Optional depth As Integer = 0) As String()
Dim folderList As String()
If (depth < 3) Then
depth += 1
folderList = recurse(depth)
Else
'Do third subfolder analysis and set the output to folderList
Return folderList
End If
End Sub