Linq Find Uncommon Items In 2 List(Of String) - vb.net

Using VB.net
I have two List(Of String)
Here's how Im finding the common items between the two lists:
Sub Main()
Dim lstOne As New List(Of String)() _
From {"Jim", "Jack", "Kate", "Nope"}
Dim lstTwo As New List(Of String)() _
From {"Jack", "Nope", "Jim"}
Dim lstNew As IEnumerable(Of String) = Nothing
lstNew = lstOne.Intersect(lstTwo, StringComparer.OrdinalIgnoreCase)
End Sub
I want to use Linq to find the uncommon items in these two lists.
How can I do that?

Like this:
Sub Main()
Dim lstOne As New List(Of String)() _
From {"Jim", "Jack", "Kate", "Nope"}
Dim lstTwo As New List(Of String)() _
From {"Jack", "Nope", "Jim"}
Dim lstNew As IEnumerable(Of String) = Nothing
lstNew = lstOne.Intersect(lstTwo, StringComparer.OrdinalIgnoreCase)
Dim uncommon As IEnumerable(Of String) = lstOne.Union(lstTwo).Except(lstNew, StringComparer.OrdinalIgnoreCase)
For Each element As String In uncommon
Console.WriteLine(element)
Next
End Sub
Output:
Kate

To stick within pure LINQ, you can use Except:
Dim inOneNotTwo As IEnumerable(Of String) = lstOne.Except(lstNew)
Dim inTwoNotOne As IEnumerable(Of String) = lstTwo.Except(lstNew)
Alternatively, you could use HashSet(Of T) and SymmetricExceptWith:
Dim strings As HashSet(Of String) = new HashSet(Of String)(lstOne)
strings.SymmetricExceptWith(lstTwo)

Related

Populate datagridview with list of strings

I need to get the data of each of the listof strings
Dim itemsRegiao As New List(Of String)
Dim itemsProduto As New List(Of String)
Dim itemsTipoAtividade As New List(Of String)
Dim itemsAcabamento As New List(Of String)
Dim itemsCores As New List(Of String)
Dim itemsGramagem As New List(Of String)
Dim itemsTipoEmbalagem As New List(Of String)
Dim itemsFormatos As New List(Of String)
Dim itemsContagem As New List(Of String)
Dim itemsTransporte As New List(Of String)
to my DataGridView1 where each column has the information of each listofstring.
So i will get 10 columns with the information that is on the list. Dont forget that if i have two String in one of the lists i have to do the combination with the others on the datagridview

Task For Each [Vb.Net]

I have a problem with System.Threading.Tasks, I don't understand why it doesn't works.
Dim table_sec As New Dictionary(Of String, List(Of Double))
table_sec.Add("SEC01", New List(Of Double)(New Double() {10.00, 5.00}))
table_sec.Add("SEC02", New List(Of Double)(New Double() {9.00, 8.00}))
table_sec.Add("SEC03", New List(Of Double)(New Double() {5.00, 2.00}))
Dim pair As KeyValuePair(Of String, List(Of Double))
Dim tasks As New List(Of Task)()
For Each pair In table_sec
Dim t As Task = Task.Run(Sub()
Console.WriteLine("Key = " & pair.Key)
End Sub)
tasks.Add(t)
Next
Task.WaitAll(tasks.ToArray())
I always get this result
Key = SEC03
Key = SEC03
Key = SEC03
Can you tell me what is wrong ?
I haven't used VB.Net in years and I can't test it, but you might try and follow the simple example of my suggested link and use a local copy of the captured reference:
Dim table_sec As New Dictionary(Of String, List(Of Double))
table_sec.Add("SEC01", New List(Of Double)(New Double() {10.00, 5.00}))
table_sec.Add("SEC02", New List(Of Double)(New Double() {9.00, 8.00}))
table_sec.Add("SEC03", New List(Of Double)(New Double() {5.00, 2.00}))
Dim pair As KeyValuePair(Of String, List(Of Double))
Dim tasks As New List(Of Task)()
For Each pair In table_sec
Dim p As KeyValuePair(Of String, List(Of Double))
p = pair ' make a copy to the actual pair in this loop iteration
Dim t As Task = Task.Run(Sub()
Console.WriteLine("Key = " & p.Key) ' capture local copy p instead of pair
End Sub)
tasks.Add(t)
Next
Task.WaitAll(tasks.ToArray())

Looping through Dictionary(Of String, List(Of String))

Similar question here, but no answer : vb.net dictionary of string,dictionary...after filling readout always empty
I fill as List(Of String) with rows of text from a file and then add it to a Dictionary. The method I use to fill this Dictionary works as it should. I create:
Private dictDictionary As Dictionary(Of String, List(Of String))
loop through the text file and adding each row to a list then add that list to the dictionary with the file name as key like so:
dictDictionary.Add(sFileName, sFileRows)
sFileRows is a List(Of String) containing a MAX of 1056 elements that I need to move around based on specific options. The problem I'm having is accessing this List(Of Strings) by the Key.
I've tried:
For Each kvp As KeyValuePair(Of String, List(Of String)) In dictDictionary
Dim sKey As String = kvp.Key
Dim tempRows As List(Of String) = New List(Of String)
tempRows = dictDictionary.item(sKey)
Next
No matter what I try when I assign the List(Of String) in the Dictionary to a new List it is always empty. But the original dictionary has the rows in the List(Of String) that I read from the text file.
First Method that fills the dictionary:
Private Sub GetInfo()
Try
Dim sFileName As String = String.Empty
Dim sFileRows As List(Of String) = New List(Of String)
If IO.Directory.Exists("some directory")Then
Dim Files() As String = IO.Directory.GetFiles("directory and file type")
For Each File As String In Files
sFileName = Path.GetFileName(File)
Dim rdrRows As StreamReader = New StreamReader(File)
Dim sString As String
While rdrRows.Peek() >= 0
sString = rdrRows.ReadLine()
sFileRows.Add(sString)
End While
'Actually adding the info to the dictionary
dictDictionary.Add(sFileName, sFileRows)
rdrRows.Dispose()
sFileRows.Clear()
Next
End If
Catch ex As Exception
End Try
End Sub
Second Method to manipulate the order of elements in the List(Of String)
Private Sub ChangeStructure()
For Each kvp As KeyValuePair(Of String, List(Of String)) In dictDictionary
Dim rows As List(Of String) = kvp.Value
For Each item As String In rows
MessageBox.Show(item.ToString)
Next
Next
End Sub
There is nothing in the List(Of String) now but there was when it was filled in GetInfo()
Should be as easy as
Dim data = New Dictionary(Of String, List(Of String)) From _
{
{"Foo", New List(Of String) From {"1", "2", "3"}},
{"Bar", New List(Of String) From {"4", "5", "6"}}
}
For Each kvp in data
Console.WriteLine(kvp.Key & " says:")
For Each str in kvp.Value
Console.WriteLine(str)
Next
Next
For Each kvp As KeyValuePair(Of String, List(Of String)) In dictDictionary
Dim rows As List(Of String) = kvp.Value
If rows Is Nothing Then Continue
For Each item As String in rows
'...
Next item
Next kvp
You're are using kvp.Key, why are you not using kvp.Value?
For Each kvp As KeyValuePair(Of String, List(Of String)) In dictDictionary
Dim sKey As String = kvp.Key
Debug.Print("Filename: " & sKey)
Dim tempRows As List(Of String) = kvp.Value
Debug.Print("# of Lines: " & tempRows.Count)
Debug.Print("------------------------------")
For Each line As String In tempRows
Debug.Print(line)
Next
Debug.Print("------------------------------")
Debug.Print("")
Next
The problem is this line:
sFileRows.Clear()
List(Of String) is a reference type. After you fill the list and add it to the dictionary, you clear it, so it is empty when you try to access it later.
The solution is to create a new list each time in the loop. In other words, move this line:
Dim sFileRows As List(Of String) = New List(Of String)
inside the For loop and get rid of the call to .Clear()

Multidimensional Arrays using Dictionaries

I am trying to make a multidimensional associative array. I want it so I can have something like:
someVar(date)(hour)(category) = mssql query
I am using the following to try and prepare but am having trouble adding data to the array.
Dim test As New Dictionary(Of Integer, Dictionary(Of String, String))
Dim test2 As New Dictionary(Of String, String)
Any help is greatly appreciated.
-----EDIT:
Here is what I am using, it works as desired. Doe ayone see why this would be a bad way to do it?
Dim test As New Dictionary(Of Integer, Dictionary(Of String, String))
Dim SomeNum As Integer = 0
Dim someStr As String = "This is a string: "
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
While SomeNum < 100
Dim someNum2 As Integer = 0
Dim test2 As New Dictionary(Of String, String)
While someNum2 < 100
test2.Add(CType(someNum2, String), someStr & CType(someNum2, String))
someNum2 += 1
End While
test.Add(SomeNum, test2)
SomeNum += 1
End While
For Each kvp As KeyValuePair(Of Integer, Dictionary(Of String, String)) In test
Dim ccc As String = ""
Dim ddd As String = ""
Dim v1 As String = CType(kvp.Key, String)
Dim v2 As Dictionary(Of String, String) = kvp.Value
lblOne.Items.Add("Key: " & v1)
For Each kvp2 As KeyValuePair(Of String, String) In v2
Dim v3 As String = kvp2.Key
Dim v4 As String = kvp2.Value
lblTwo.Items.Add("SubKey: " & v3 & " Value: " & v4)
lblOne.Items.Add("")
Next
lblOne.Items.Add(v1 & " End--------------")
lblTwo.Items.Add(v1 & " End--------------")
Next
End Sub
Create a class with properties "Date", "HourlySales", "Category".
Public Class Sales
Public Property SalesDate() As Date
Public Property HourlySales() As Decimal
Public Property Category() As String
Public Sub New()
End Sub
Public Sub New(vSalesDate As Date, vHourlySales As Decimal, vCategory As String)
SalesDate = vSalesDate
HourlySales = vHourlySales
Category = vCategory
End Sub
End Class
Create a list of objects of type Sales
Shared Function GetSales() As List(Of Sales)
Dim SalesList As New List(Of Sales)
Using connection As New SqlConnection(YourConnectionString)
Dim cmd As SqlCommand = New SqlCommand("SelectSalesList", connection)
cmd.CommandType = CommandType.StoredProcedure
cmd.Connection.Open()
Dim reader As SqlDataReader = cmd.ExecuteReader()
While reader.Read
SalesList.Add(New Sales(reader("SalesDate"), reader("HourlySales"), reader("Category")))
End While
End Using
Return SalesList
End Function
You can call the GetSales() function to return a list of Sales.
Look into Entity Framework it makes objects out of your database.
MSDN EF
For a custom array, you may find a Tuple useful.
A dictionary of dictionary of dictionaries is a maintenance nightmare, to query and debug.
I suggest to have a composite key instead, so instead of doing 3 lookups you would just do one for a string of date+hour+category. For example, date=Monday, hour=9PM, category=Apples, your key is Monday:9PM:Apples (I picked colon as parts separator, but you can choose a different character).

Short-cut when adding items to a list

In some languages there are short-cuts when adding items into collections.
I have the following:
Sub Main()
Dim letters As List(Of String)
letters = New List(Of String)
letters.Add("a")
letters.Add("1")
letters.Add("2")
letters.Add("3")
letters.Add("x")
letters.Add("d")
End Sub
Is there a short hand way of executing this. The following does not work but maybe there's some similar syntax in VB.NET:
Sub Main()
Dim letters As List(Of String)
letters = New List(Of String){"a","1","2","3","x","d"}
End Sub
Since VS2010 you should be able to do this in VB.NET:
Dim letters As List(Of String)
letters = New List(Of String) From {"a","1","2","3","x","d"}
The From can be swapped for brackets:
letters = New List(Of String) ({"a","1","2","3","x","d"})
Nice related article: MSDN HERE
You could use a string array (input() in my example). Another option is pass the list of strings to the constructor or use List.AddRange.
Dim input() As String = { "A", _
"B", _
"C" }
Dim listA As New List(Of String)(input)
dim listB as New List(Of String)
listB.AddRange(input)
HTH Wade