Find Array index that contains string - arrays

I have file with tags and targets, this is example:
TAG1|TARGET1,TARGET2
TAG2|TARGET3,TARGET4
I start by creating String Array using File.ReadAllLines
Dim MAIN As String() = File.ReadAllLines("")
At some point I have one of targets and I need to know what was the tag index (which array line is it), so for example if I have TARGET3 I want to know it's in second line so it's in MAIN(1) and then I can grab TAG = TAG2.
I can't get it working, I tried few methods:
Array.IndexOf(MAIN,"TARGET3")
always returned -1, it worked with full string tho,
Array.IndexOf(MAIN,"TAG2|TARGET3,TARGET4")
returned 1. I tried with Array.FindIndex, was the same.
So my question is: how to get index of partial array item. Thank you for any help.

You can use Linq to search your array in this way
Dim search = "TARGET3"
Dim line = MAIN.FirstOrDefault(Function(x) x.Contains(search))
This will return directly the line with the matching word

Related

Is there a way to make an empty array and growing it as it gets data in vb.net?

I have been working on a project, and am attempting to make a new array for data. I have tried making an empty array with Dim Name() As String = {}. I am using a ListView, and the way I have done it there are blank spots where I have gotten rid of data. This is my current code:
Sub English(ByVal Country() As String, ByVal Language() As String)
rbDisplayallData.Checked = False
lstResults.Visible = True
lstResults.Items.Clear()
lstResults.Columns.Clear()
With lstResults
.View = View.Details
.Columns.Add("English Speaking Countries", 200, HorizontalAlignment.Left)
End With
For i = 0 To 181
Dim EnglishSpeakingCountries(i) As String
If Language(i) = "English" Then
EnglishSpeakingCountries(i) = Country(i)
End If
lstResults.Items.Add(New ListViewItem({EnglishSpeakingCountries(i)}))
Next
End Sub
I am trying to get rid of these spaces.
I Was thinking if I were to compact the array or make a new one with the same data going into a new array it would fix the issue.
If you have a solution please let me know.
There are two things that could be considered an empty array
An array with no elements, i.e. a Length of zero.
An array where every element is Nothing.
All arrays are fixed-length. Once you create an array with a particular number of elements, it always has that number of elements. You can use ReDim Preserve or Array.Resize but, in both those cases, what actually happens is that a new array is created and the elements copied from the old array. The new array is assigned to the same variable but anywhere the old array is referenced, it will still have that same number of elements. Try running this code to see that in action:
Dim a1 As String() = {}
Dim a2 As String() = {"First", "Second", "Third"}
Dim b1 = a1
Dim b2 = a2
Console.WriteLine(a1.Length)
Console.WriteLine(a2.Length)
Console.WriteLine(b1.Length)
Console.WriteLine(b2.Length)
Console.WriteLine()
ReDim Preserve a1(2)
Array.Resize(a2, 6)
Console.WriteLine(a1.Length)
Console.WriteLine(a2.Length)
Console.WriteLine(b1.Length)
Console.WriteLine(b2.Length)
Console.ReadLine()
Output:
0
3
0
3
3
6
0
3
As you'll be able to see, a1 and a2 end up referring to new arrays with the specified lengths but the original arrays with the original lengths still exist and are still accessible via b1 and b2.
If you start with an array with no elements then you can use ReDim Preserve or Array.Resize to give the appearance of resizing the array but that's not really what's happening and that should generally be avoided. If you know how many elements you'll end up with then you could create an array of that size and then set each element in turn. You'd need to keep track of the next element index though, so that's still a bit tedious.
Generally speaking, if you want an array-like data structure but you want it to be able to grow and shrink as required, you should use a collection. The most common collection is the List(Of T), where T is any type you care to specify in your code. If you want to store String objects then use a List(Of String). You can call Add to append a new item to the end of the list, as well as Insert, Remove and RemoveAt methods. You can also get or set an item by index, just as you can do for array elements.
Note that a List(Of T) actually uses an array internally and uses the aforementioned method of "resizing" that array. It optimises the process somewhat though, which makes the code easier for you to write and large collections more efficient to use.
It's worth noting that, in your own code, the Columns and Items properties of your ListView are both collections, although they are slightly different to the List(Of T) class.
Looking at your original code, this:
For i = 0 To 181
Dim EnglishSpeakingCountries(i) As String
If Language(i) = "English" Then
EnglishSpeakingCountries(i) = Country(i)
End If
lstResults.Items.Add(New ListViewItem({EnglishSpeakingCountries(i)}))
Next
could be changed to this:
Dim englishSpeakingCountries As New List(Of String)
For i = 0 To 181
If Language(i) = "English" Then
englishSpeakingCountries.Add(Country(i))
lstResults.Items.Add(Countries(i))
End If
Next
Note that you're just adding items to two collections. I guess the question is whether you actually need this extra collection at all. If you do want to use it later then you need to assign it to a member variable rather than a local variable. If you don't need it later then don't create it at all. As I said, you're already adding items to a collection in the ListView. Maybe that's all you need, but you haven't provided enough info for us to know.

How to parse and address a json matrix array in Excel-VBA?

I need to parse JSON text to a JSON object in Excel-VBA. The JSON text includes a matrix/array. Then I need to address it (set a VBA variable to the value).
My code had been working parsing a nested/keyed JSON text with "JsonConverter.parseJSON" method. But I do not know how to address new array object (or technically if the "parse" is working correctly.
Dim jsonResults As String
Dim jsonObj As Dictionary
Set travelDist As Number
Set jsonResults = '{"distances":[[0,97641],[97415,0]],"times":[[0,4189],[4183,0]],"weights":[[0.0,5653.726],[5644.176,0.0]],"info":{"copyrights":["GraphHopper","OpenStreetMap contributors"]}}'
Set jsonObj = JsonConverter.ParseJson(jsonResults) \This worked with the old JSON text keyed value structure.
travelDist = VBA.Val(jsonObj.Item("distances")(1)) \This DOESN'T work. It worked with Keyed Object Values. The goal is to set travelDist to in this example, 97641.
The current code seems to have a type mismatch.
The goal is to set a VBA variable to 97641. Please let me know how to include required files/definitions etc. if the solution is including additional types or methods.
There's no reason to declare jsonObj as a dictionary and unless Number is a well defined user-defined type of some sort, I don't think declaring travelDist as Number will work. Use Double instead. And always use Option Explicit on the very top.
Also the double quotes in the JSON string need to be escaped somehow. You can either double them:
jsonResults = "{""distances"":[[0,97641],[97415,0]],""times"":[[0,4189],[4183,0]],""weights"":[[0.0,5653.726],[5644.176,0.0]],""info"":{""copyrights"":[""GraphHopper"",""OpenStreetMap contributors""]}}"
or replace them with single quotes:
jsonResults = "{'distances':[[0,97641],[97415,0]],'times':[[0,4189],[4183,0]],'weights':[[0.0,5653.726],[5644.176,0.0]],'info':{'copyrights':['GraphHopper','OpenStreetMap contributors']}}"
or you can just store the string in a cell in one of your worksheets and load it from there:
Dim sht As Worksheet
Set sht = ThisWorkbook.Worksheets("Name of your Worksheet")
Set jsonObj = JsonConverter.ParseJson(sht.Range("A1"))
Visualizing the JSON structure might help you understand it better:
So basically what you need to do is access the 2nd item, of the 1st item, of the distances array/collection, keeping in mind that the 1st item of the distances array is also an array/collection itself.
The way to do this would be the following:
Option Explicit
Sub test()
Dim jsonObj As Object
Dim jsonResults As String
Dim travelDist As Double
jsonResults = "{""distances"":[[0,97641],[97415,0]],""times"":[[0,4189],[4183,0]],""weights"":[[0.0,5653.726],[5644.176,0.0]],""info"":{""copyrights"":[""GraphHopper"",""OpenStreetMap contributors""]}}"
Set jsonObj = JsonConverter.ParseJson(jsonResults)
travelDist = jsonObj("distances")(1)(2)
Debug.Print travelDist 'the result is printed in the immediate window
End Sub
Finally, I assume that since you've used this before, you know you need to add this JSON parser to your project, as well as a reference to Microsoft Scripting Runtime (VBE>Tools>References>...)

Check if a string contains all other strings

I am trying to code a part of a software where I try to show the results that match search criteria.
I have a textbox where I can type one or more words I want to search and a listview that contains 4 different columns and a dozen rows. The idea is that each listview row contains lots of words and I want to see only the rows that contain all the words I have typed in the textbox. I have finished the code that searches for one term only. The problem I am having is that I don't fully understand how to do the same, but using multiple terms instead of one term only.
In the textbox, I write the words I want to search separated by a space. I have a variable where I keep the whole content of the listview row separated by : (example => col1row1content:col1row2content:col1row3content,etc). Summarizing, I want to check if a string (the full content of a row) contains all other strings (each word I have typped in the textbox).
This is the code I have implemented:
Dim textboxFullContentArray As String() = textboxSearch.Split(New Char() {" "c})
Dim Content As String
Dim containsAll As Boolean = False
Dim wholeRowContent(listviewMain.Items.Count - 1) As String ' each index of the array keeps the entire row content (one array contains all 4 cells of the row)
' wholeRowContent contains in one index the entire content of a row. That means,
' the index contains the 4 cells that represent an entire row.
' The format is like "rowData1:rowData2:rowData3:rowData4" (omitted for simplicity)
For Q As Integer = 0 To listviewMain.Items.Count - 1
For Each Content In textboxFullContentArray
If wholeRowContent(Q).ToLower.Contains(Content) Then
containsAll = True
' rest of the code...
ElseIf Not wholeRowContent(Q).ToLower.Contains(Content) Then
containsAll = False
Exit For
End If
Next
Next
But of course, this code is showing false positives and I think it's not a good solution. I think it must be much easier and I am overcomplicating the concept.
I am using VB.Net 2013
You can determine whether a String contains all of a list of substrings with a single line of code:
If substrings.All(Function(s) str.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0) Then
Notice that I have actually implemented a case-insensitive comparison, rather than using ToLower or ToUpper.
It may not seem as neat to call IndexOf rather than Contains but guess what: Contains actually calls IndexOf internally anyway:
public bool Contains(string value)
{
return this.IndexOf(value, StringComparison.Ordinal) >= 0;
}
You can write your own extension methods if you want a case-insensitive Contains method:
<Extension>
Public Function Contains(source As String,
value As String,
comparisonType As StringComparison) As Boolean
Return source.IndexOf(value, comparisonType) >= 0
End Function
Your If/Else looks like it could be simplified. I would set your containsAll value to true outside the nested loops, and only if you encounter a "Content" in "textboxFullContentArray" that is not contained in wholeRowContent(Q) you set containsAll to false, otherwise do nothing.
Also, one way to see what's going on is to print statements with the values that are being compared throughout your function, which you can read through and see what is happening at runtime when the false positives occur.
After some hours looking for a simple and effective solution (and trying different codes), I have finally found this solution that I adapted from: Bad word filter - stackoverflow
For Q As Integer = 0 To listviewMain.Items.Count - 1
If textboxFullContentArray.All(Function(b) wholeRowContent(q).ToLower().Contains(b.ToLower())) Then
' my code
End If
Next

String array not accepting a string

I'm trying to make a simple login program, but I'm having troubles with assigning a value to my two arrays "User()" and "Pass()". I have the following code on a form titled "frmCreate". This is the form I will be using to create the accounts.
Public Class frmCreate
Dim passs() As String
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnCreate.Click
If Not (txtUser.Text = "") And Not (txtPass.Text = "") Then
userCount = userCount + 1
User(userCount) = txtUser.Text
Pass(userCount) = txtPass.Text
Else
MsgBox("Please enter a username or password")
End If
End Sub
Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
passs(0) = "hi"
End Sub
End Class
The issue I'm getting is as follows:
Error in array
The txtPass and txtUser are both text boxes, which can be edited by the user.
Any help would be much appreciated! (Also, I tried mucking around with the variables and all, the strings after the = sign aren't the problem, and when I set the "userCount" inside the brackets to "0" for example, it still returned the same error)
EDIT Added code as text, rather then image (image still there). Note the extra few lines at the end where I set a new array which I named passs() to "hi". The dim is also further up. If I am declaring my variables incorrectly, please let me know.
EDIT2 Ok, I changed my declaration of "User()" and "Pass()" to = {}. Now my problem is that I'm getting the error that the value is out of the bounds of the array. I understand that this happens when you try to call on a non existent value which is outside the arrays boundaries, but the array I set has no boundaries, and I'm just trying to give it a value, not call on one.
EDIT3 Ugh... Ok tweaked a bit, I've found that if I add an unused value to "User()" then it is able to replace it. So I can get the program to replace already existent values in arrays, but I can not get it to create new values in arrays.
It would appear your User variable is NULL. I presume this is intended to be a list of strings or something similar?
You should check the place you are initializing this variable to make sure it is being created...
You could add an
If User Is Nothing
line at the start of the function to check this, and if the list is null at this point create it.
I have discovered what it is I was doing wrong. See, I thought when I declared a variable with empty parenthesis, it created a dynamic variable. This is obviously not the case. Since setting the size of my variable to the ludicrous size of 50,000, my program now works. Thanks to all who tried to help, and sorry for asking the wrong thing :/
Your problem here is that you only defined the variable array. You never reserved a spot for the array values in memory. Therefore your variable has a value of Nothing.
Before assigning the first item, you must assign room for it...
'We say we want an array
Dim passs() As String
'We ask the memory to reserve six spots for our array
passs = New String(5) {}
'We assign the first spot to the String "hi"
passs(0) = "hi"
However, if you don't know how many items you are going to add in your array, I strongly suggest you to use a List(of T) instead :
Dim passs As New List(of String)
passs.Add("hi")

Error when checking if an array element actually hold data

I have a short app that check if my music files are names to a specific routine (track number and then track name), but I'm getting an error whenever there are no files that need renaming, because the array in initialised, but the first item is nothing, null, empty (however VB refers to it).
To try and fix this, I'm running this check, but I'm still getting an error.
' Array declared like this
Dim nc_full_names(0) As String
<Code goes here to ReDim 'nc_full_names' and add the file name to the array, if a file needs renaming>
For i = 0 To UBound(nc_full_names)
'Checking if the array element actually has something in it like this
If Not nc_full_names Is Nothing Then
My.Computer.FileSystem.RenameFile(nc_full_names(i), nc_new_names(i))
Else
Exit For
End If
Next i
Here is the error that I am getting -
Argument cannont be nothing. Parameter name: file
Can anyone tell me the correct way to carry out this check?
I found that the answer was to check the first element in the array, as opposed the array itself. Thus, changing this...
If Not nc_full_names Is Nothing Then
...to this...
If Not nc_full_names(i) Is Nothing Then
...works just fine.
You can also start with a truly empty array:
Dim nc_full_names(-1) As String
Now nc_full_names.Length = 0.

Resources