Randomize strings in a list - vb.net

Dim myRandom As New Random
Dim myList As New List(Of String)(New String() {"A", "B", "C"})
myList.OrderBy(Function(i) myRandom.Next).ToList()
For k As Integer = 0 To 2
MessageBox.Show(myList.Item(k))
Next
When you run the code, you will see that the MessageBoxes show A,B,C.
I want MessageBoxes show B,C,A or C,B,A or A,C,B or A,B,C or B,A,C or C,A,B according to randomized result.
Note: Using Linq is a must.

The issue is that your code doesn't make any changes to myList. A LINQ query ALWAYS generates a new list. You need to assign the result of ToList back to your myList variable, i.e.
myList = myList.OrderBy(Function(i) myRandom.Next).ToList()

Related

Variables refer to the same instance

Within my learning curve I play around with converting List and IEnumerable between each other.
What I am surprised with is that after executing EditMyList procedure MyIEnumerable contains the same data for each DBTable object as MyList. However I have modified MyList only, without assigning it to MyIEnumerable once List has been modified.
Can you explain what happened here and why MyList and MyEInumerable refer to the same instance?
Public Class DBTable
Public Property TableName As String
Public Property NumberOfRows As Integer
End Class
Public Sub EditMyList
Dim MyList As New List(Of DBTable)
MyList.Add(New DBTable With {.TableName = "A", .NumberOfRows = 1})
MyList.Add(New DBTable With {.TableName = "B", .NumberOfRows = 2})
MyList.Add(New DBTable With {.TableName = "C", .NumberOfRows = 3})
Dim MyIEnumerable As IEnumerable(Of DBTable) = MyList
For Each item In MyList
item.NumberOfRows += 10
Next
End Sub
UPDATE: string case where at the end b is not equal to a. String is also reference type, so assigning one variable to other one we shall copy just reference. However at the end there is different result than in the first example (explained by #Sefe)
Dim a As String
Dim b As String
a = "aaa"
b = "bbb"
a = b
' At this point a and b have the same value of "bbb"
a = "xxx"
' At this point I would expect a and b equal to "xxx", however a="xxx" but b="bbb"
A List is a reference type. That means it is created on the heap and your MyList variable contains just a reference (sometimes incorrectly called "pointer") to the list. When you assign MyList to MyEnumerable you don't copy the whole list, you just copy the reference. That means all changes you make to the (the one) list, is reflected by all the references.
If you want a new list you need to create it. You can use the list constructor:
Dim MyIEnumerable As IEnumerable(Of DBTable) = New List(Of DBTable)(MyList)
Since you don't need a list, but an IEnumerable you can also call the list's ToArray method:
Dim MyIEnumerable As IEnumerable(Of DBTable) = MyList.ToArray
You can also use LINQ:
Dim MyIEnumerable As IEnumerable(Of DBTable) = MyList.ToList
As far as the behavior of String is concerned, strings in .net are immutable. That means once created, they can not be changed. String operations (for example concatinations) will always create new strings. In other words: the copy operation you have to do manually for your lists is done automatically for strings. That's why you see similar behavior for strings as for value types.
Also, the assignment operation in your question would also still behave the same if strings were mutable. When you assign a = "xxx", you update the reference of afrom "bbb" to "xxx". That however does not affect b, which still keeps its old reference.
Use ToList() extension method for creating another List
Dim newCollection = MyList.ToList()
But notice that instances of DBTable still will reference to the same items
For creating "full" copy you need create new instances of DBTable for every item in the collection
Dim newCollection = MyList.Select(Function(item)
return new DBTable
{
.TableName = item.TableName,
.NumberOfRows = item.NumberOfRows
}
End Function).ToList()
For Each item in MyList
item.NumberOfrows += 10 ' will not affect on the newCollection items
Next

Compare 2 ArrayLists and remove duplicates

I am looking to compare values of 2 different ArrayLists, and remove any duplicates from 1 ArrayList.
Example:
Arr1 = {HF,HA,GM,RV}
Arr2 = {FB,HA}
Since they have 'HA' in common, I would like to remove 'HA' from Arr1. Any help or point in the right direction would be appreciated.
You can use LINQ's Except but you will have to convert array lists to regular arrays first:
https://msdn.microsoft.com/en-us/library/bb300779(v=vs.110).aspx
Dim list1 As New ArrayList()
list1.Add("A")
list1.Add("B")
list1.Add("C")
Dim list2 As New ArrayList()
list2.Add("A")
list2.Add("B")
Dim array1 = list1.ToArray()
Dim array2 = list2.ToArray()
Dim except = array1.Except(array2).ToArray()
Also if you need a custom comparison, use this overload instead:
https://msdn.microsoft.com/en-us/library/bb336390(v=vs.110).aspx
EDIT
There are very few LINQ methods available for ArrayList, however you can convert it back very easily:
Dim arrayList as New ArrayList(except)

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

VB: List(Of List(Of String)) keeps changing the content of the outer list when I change the inner one?

I'm writing a program in VB, and I need to make a list of lists (I've already figured out how to do that one). The problem is, the outer list is going to need a different number of elements depending on other variables elsewhere in the program.
I've looped this code:
Dim rep As Long = 1023
Dim items As List(Of String)
items.Add("First Entry")
items.Add("Second Entry")
items.Add("Third Entry")
items.Add("Fourth Entry")
'(sake of argument, these are the variables
'that will be changing vastly earlier
'in the program, I put them in this way to simplify
'this part of my code and still have it work)
Dim myList As New List(Of List(Of String))
Dim tempList As New List(Of String)
For index = 1 To Len(rep.ToString)
tempList.Add(items(CInt(Mid(rep.ToString, index, 1))))
Next
myList.Add(tempList)
tempList.Clear()
My issue is with that last part; every time I add the tempList to myList, it's fine, but when I clear tempList, it also clears the version of tempList in myList.
myList will have a count of 1, but the list inside it has a count of 0 as soon as I clear tempList. And I have to clear tempList because I'm looping this section of code over and over, a variable number of times.
Is there a way around this? Am I being a horrible noob?
You're using the same tempList each time, instead of making a new one.
You likely need to do:
myList.Add(tempList)
tempList = new List(Of String) ' Create a new List(Of T), don't reuse...

VB.NET Multi-Dimentional Array

Alright, so I'm used to PHP where I can declare a multi-level array like $something[0][1] = "test";. I need to be able to accomplish the same thing, but I'm using VB.NET. How would I do this?
And sorry if this isn't what a multi-dimentional array is, I might be wrong at what it's called but that's what I want to do.
Thanks!
Multidimensional array in VB.Net...
Dim twoDimensionalArray(10, 10) As String
twoDimensionalArray(0, 1) = "test"
I rarely use arrays, however. More elegant solutions can typically be achieved using Lists, Dictionaries, or combinations of the two.
Update .
The (10, 10) is the upper bound of the array (the size is actually 11, 0 through 10). If you don't specify the bounds, you have to Redim Preserve the array when you want to add to it. That's one good thing about lists, you don't have to specify an initial size and you can add to them freely.
Here's a quick example of a list of lists.
Dim listOfLists As New List(Of List(Of String))
listOfLists.Add(New List(Of String)(New String() {"a", "b", "c"}))
listOfLists.Add(New List(Of String)(New String() {"d", "e", "f"}))
listOfLists.Add(New List(Of String)(New String() {"g", "h", "i"}))
'listOfLists(0)(0) = "a"
'listOfLists(0)(1) = "b"
'listOfLists(2)(1) = "h"
Just a plain sample with dynamic resizing of the array
Dim arr(0)() As String '** array declaration
For i As Integer = 0 To 100 '** Outer loop (for the 1st dimension)
For j As Integer = 0 To 1 '** inner loop (for the 2nd dimension)
ReDim Preserve arr(i) '** Resize the first dimension array preserving the stored values
ReDim Preserve arr(i)(j) '** Resize the 2nd dimension array preserving the stored values
arr(i)(j) = String.Format("I={0},J={1}", i, j) '** Store a value
Next
Next
In .NET Arrays are usually static and won't be automatically resized. (As for example in Javascript etc.) Therefore it's necessary to manually resize the array each time you want to add a new item, or specify the size at the beginning.