How to loop through two lists simultaneously? - vb.net

I have referred to the following question at: Using foreach loop to iterate through two lists. My question is this, with regards to the chosen answer: Can the o.DoSomething be a comparison? As in:
For Each a in ListA.Concat(ListB)
If(a from ListA=a from ListB) Then
Do Something here
End If
Next
As you might've guessed, I'm using VB.Net and would like to know how I can do what I have shown here. That would basically be to iterate through a joined list separately/independently. Thanks!

Your question indicates that you need a Join operation, because it's not that you want to iterate over two lists, but you also want to match like items from one list to the other.
Dim joinedLists = From item1 In list1 _
Join item2 In list2 _
On item1.Bar Equals item2.Bar _
Select New With {item1, item2}
For Each pair In joinedLists
'Do work on combined item here'
'pair.item1'
'pair.item2'
Next
Other answers recommend Zip. That is simply a function that takes two sequences and produces a single result, much like join, but it is geared to work in a FIFO method over both lists. If you need connections made based on an equality, Join is the specifically built to be right tool for this job.

The answers to my question is-it-possible-to-iterate-over-two-ienumerable-objects-at-the-same-time may help
Dim listA As List(Of A)
Dim listb As List(Of B)
listA.Zip(listb, Function(a, b) a.property1 = b.property1).ForEach(AddressOf Print)
Shared Sub Print(ByVal s As A)
Console.WriteLine(s.Property1)
End Sub

In .Net 4 you could use Zip. Adapted from my answer to this question from a Python fan specifically asking for tuples - you could remove the tuples if you like.
Sub Main()
Dim arr1() As String = {"a", "b", "c"} '' will also work with Lists
Dim arr2() As String = {"1", "2", "3"}
For Each t In TupleSequence(arr1, arr2)
If t.Item1 = t.Item2 Then
'' Do something
End If
Next
Console.ReadLine()
End Sub
Function TupleSequence(Of T1, T2)(
ByVal seq1 As IEnumerable(Of T1),
ByVal seq2 As IEnumerable(Of T2)
) As IEnumerable(Of Tuple(Of T1, T2))
Return Enumerable.Zip(seq1, seq2,
Function(s1, s2) Tuple.Create(s1, s2)
)
End Function

On solution would be to have a dictionary with items from the second list, then loop through your first list and retrieve the corresponding item in the second one, using the dictionary. Here's an example, assuming you want to compare items with an ID property:
Dim DictB = ListB.ToDictionary(Function(x) x.ID)
For each itemA in ListA
If DictB.ContainsKey(itemA.ID)
'Item is in both lists
Dim itemB = DictB(itemA.ID)
'Do something here
End If
Next

Related

VB.NET copy a 2-dimenion List into a one dimension list

In my original code I have a list object containing 2 columns, Word and Percent. I sort the list but only want to return the list containing just the Word
Here is some example code broken down into something simple:
Public Function SortMyWords() as list(of string)
Dim Words As WordsToSort
Dim ListofWords As New List(Of WordsToSort)
Words.Word = "John"
Words.Percent = "10"
ListofWords.Add(Words)
Words.Word = "Robert"
Words.Percent = "1"
ListofWords.Add(Words)
ListofWords = ListofWords.OrderBy(Function(x) x.Percent).ToList()
End Sub
Public Structure WordsToSort
Public Word As String
Public Percent As String
Public Sub New(ByVal _word As String, ByVal _percent As String)
Word = _word
Percent = _percent
End Sub
End Structure
At the end of the SortMyWords function, I want to return just the Word column back as a list, I'm not sure if I can do this direct - i.e.
Return Listofwords(column Word) or whether I need to copy my ListofWords into a new list, just containing the Column Word - something like this (which doesn't work)
Dim Newlist As New List(Of String)
Newlist.AddRange(ListofWords(Words.Word))
Return NewList
Any suggestions on whether I should do this completely differently (and better) would be really appreciated as I am trying to get my head around objects and although I use them all the time, I'm new to structures and list objects.
Thanks for any help, this has been driving me crazy for an hour now.
I think you're close. Try:
ListOfWords
.OrderBy(Function(x) x.Percent)
.Select(Function(x) x.Word)
.ToList()
If you prefer, you can also use the LINQ syntax:
(from w in ListOfWords
orderby w.Percent ascending
select w.Word).ToList()
Note that the return type is a List(Of String) and not a List(Of WordsToSort) anymore. So you cannot assign it back to the variable ListOfWords again like you do in your sample code.

ItextSharp : Adding cells to table using loop

As I am new to ItextSharp, I am trying to change the existing functionality on how the cells are added to PdfPTable .. currently the cells are added row wise, I want them to be added column wise with the help of a loop.
There are two lists, the first list fills the first column, the second list fills the whole of second column. If the lists have unequal rowcount, I have to add empty cells against those columns.
I tried doing some research on web for this but couldnt find a suitable solution.
Can someone provide an example to achieve this?
I'm not going to answer with anything iText specific since this is more of a general programming problem. The basic idea is that you need to find the maximum count of the two lists, loop from zero to that maximum, and check each list to see if that value falls in range. If it is in range, use the value and if it isn't, create your empty cell. Below is a very simple implementation of this:
''//Two sample lists
Dim ListA As New List(Of String) From {"A", "B", "C"}
Dim ListB As New List(Of String) From {"Apple", "Bat"}
''//Find the maximum count of the two lists
Dim X = Math.Max(ListA.Count, ListB.Count)
''//Index notations are zero-based so loop from zero to one
''//less than the total
For I = 0 To (X - 1)
If I >= ListA.Count Then
''//Our index is past the limit of the first column, add empty cell here
Console.WriteLine("<A>")
Else
''//Our index is within the limits of the first column
Console.WriteLine(ListA(I))
End If
If I >= ListB.Count Then
''//Our index is past the limit of the second column, add empty cell here
Console.WriteLine("<B>")
Else
''//Our index is within the limits of the first column
Console.WriteLine(ListB(I))
End If
Next
EDIT
If you have more than just two columns you can extrapolate this to something like the below:
Dim ListA As New List(Of String) From {"A", "B", "C"}
Dim ListB As New List(Of String) From {"Apple", "Bat"}
Dim ListC As New List(Of String) From {"Alice", "Bob", "Charlie", "Daniel"}
Dim AllLists As New List(Of IEnumerable(Of Object))
AllLists.Add(ListA)
AllLists.Add(ListB)
AllLists.Add(ListC)
Dim Z = AllLists.Max(Function(l) l.Count)
For I = 0 To (Z - 1)
For Each L In AllLists
If I >= L.Count Then
Console.WriteLine("<BLANK>")
Else
Console.WriteLine(L(I).ToString())
End If
Next
Next

How to merge two list to have a distinct list without duplicate values in vb.net

I have this problem in vb.net. Lets say I got 2 Lists ListA and ListB both holds objects of same type.
Eg., one of the property of the object is ID. (ID is written in brackets)
ListA ListB
---------------------------
A(3818) A(3818)
B(3819) B(3819)
C(3820) C(3820)
D(3821) D(3821)
E(3823) F(0)
H(3824) G(0)
I(3825)
How do I merge these two Lists to have a new distinct list which holds objects only once whose ID matches and all other objects(whose ID dont match) are simply added to the new list.
Sample output be,
New List
--------
A(3818)
B(3819)
C(3820)
D(3821)
E(3823)
F(0)
G(0)
H(3824)
I(3825)
When I searched I found that AddRange() and Union are some of the methods to do the merge. But i am not able to find if this works for non standard objects(apart from Integer, String)
Use addRange() and then linq with distinct to filter out the duplicates.
Dim b = YourCollection.Distinct().ToList()
Could use a collection bucket
Dim oCol As New Collection
AddTitems(oCol, oListA)
AddTitems(oCol, olistB)
Public Function AddTitems(oSummaryList As Collection, oList As List(Of thing)) As Collection
For Each oThing As thing In oList
If Not oSummaryList.Contains(CStr(oThing.ID)) Then oSummaryList.Add(oList, CStr(oThing.ID))
Next
Return oSummaryList
End Function
Here are a couple simple functions that should do that for you. I'm not sure how efficient they are though. I don't think there is anything built in.
Private Function nameOfFunction(list1 as list(of type), list2 as list(of type)) as list(of type)
Dim result as new list(of type)
for a as integer = 0 to math.max(list1.count, list2.count) - 1 step 1
If a < list1.count AndAlso resultHasID(result, list1(a).ID) = False Then
result.add(list1(a))
end if
If a < list2.count AndAlso resultHasID(result, list2(a).ID) = False Then
result.add(list2(a))
end if
next
End Function
Private Function resultHasID(testList as list(of type), s as string) as boolean
Dim result as Boolean = False
for a as integer = 0 to testlist.count - 1 step 1
if(testlist(a).ID = s) then
result = true
exit for
End if
Next
Return result
End function
For each item as String in ListA
If Not ListB.Contains(item) Then
ListB.Add(item)
End If
Next

Is there a way to loop over multiple variables in a for each loop in vb.net?

I would like to loop over two string arrays but does not work.
Would probably look something like the following:
For Each (s1, s2) As (String, String) In (stringArray1, stringArray2)
Is there something similar to python tuples that I could use?
I think that vb.net don't support this in this way.
If you have two IEnumerables, you can do something like this
Using lst1 As IEnumerator(Of X) = List1.GetEnumerator(),
lst2 As IEnumerator(Of Y) = List2.GetEnumerator()
While lst1 .MoveNext() AndAlso lst2 .MoveNext()
If lst1 .Current.Equals(lst2 .Current) Then
''Put here your code.
End If
End While
End Using
For a better explanation, check this related link: Is it possible to iterate over two IEnumerable objects at the same time?
In .Net 4 you could use Zip and tuples.
Sub Main()
Dim arr1() As String = {"a", "b", "c"}
Dim arr2() As String = {"1", "2", "3"}
For Each t In TupleSequence(arr1, arr2)
Console.WriteLine(t.Item1 & "," & t.Item2)
Next
Console.ReadLine()
End Sub
Function TupleSequence(Of T1, T2)(
ByVal seq1 As IEnumerable(Of T1),
ByVal seq2 As IEnumerable(Of T2)
) As IEnumerable(Of Tuple(Of T1, T2))
Return Enumerable.Zip(seq1, seq2,
Function(s1, s2) Tuple.Create(s1, s2)
)
End Function
Not as nice as the Python though.
If they are the same length you could do something like...
dim i as integer = 0
do until i = s1.length
dim s1Value as string = s1(i)
dim s2Value as string = s2(i)
i += 1
loop
I have studied the same question before, but found no beautiful way for coding in VB.Net. But I think it is not necessary do the same as in Python, Tcl, etc. So I just use a For-Loop, similar to Jack's answer. This also works for List.
'List1.Count = List2.Count
For i as Integer = 0 To List1.Count - 1
'Work on List1.Item(i) and List2.Item(i)
Next

Display all contents of a "table" created in LINQ in VB.NET

Working from a previous question I asked (which was answered very well).. Ive come across another snag... In the following code
Public Sub Main()
Dim EntireFile As String
Dim oRead As System.IO.StreamReader
oRead = File.OpenText("testschedule.txt")
EntireFile = oRead.ReadToEnd
Dim table As New List(Of List(Of String))
' Process the file
For Each line As String In EntireFile.Split(Environment.NewLine)
Dim row As New List(Of String)
For Each value In line.Split(",")
row.Add(value)
Next
table.Add(row)
Next
' Display all contents of 5th column in the "table" using LINQ
Dim v = From c In table Where c(5) = ""
For Each x As List(Of String) In v
Console.WriteLine(x(0)) ' printing the 1st column only
Next
Console.WriteLine("Value of (2, 3): " + table(1)(2))
End Sub
`
The area where it says Dim v = From c In table Where c(5) = "" the blank quotations will only accept a specific number that its looking for in that column.
For Example:
Dim v = From c In table Where c(5) = "7" Will only show me any 7's in that column. Normally there will be many different values and I want it to print everything in that column, I just cant figure out the command to have it display everything in the selected column
Once again Many MANY Thanks!
If you want to show all rows (to be precise: items in the IEnumerable), just remove the Where condition
Dim v = From c In table
Just a note: table is not a very good name for your list, it leads the thought to SQL. This is just Linq2Objects and you don't query tables you query plain objects with a syntax very similar to Linq2SQL that in turn is heavily inspired by SQL.