Exception was thrown when adding new rows to datatable - vb.net

listA is list of integer
dtListB is DataTable
I'm checking that if StudentId of ListA doesn't exist in dtListB, then add it to the dtListB.
Dim stidListA, stIdListB As Integer
For Each la In listA
stidListA = la.StudentId
For n = 0 To dtListB.Rows.Count - 1 Step 1
stIdListB = dtListB.Rows(n)("StudentId")
If stIdListB <> stidListA Then
dtListB.Rows.Add(New Object() {la.StudentId, la.AssignedId, la.TimeSheetId, 0})
End If
Next
Next
I'm not sure why the error is thrown :
Exception of type 'System.OutOfMemoryException' was thrown.
dtListB.Rows.Add(New Object() {la.StudentId, la.AssignedId, la.TimeSheetId, 0})
Any suggestion? Thanks.

You are iterating with dtListB.Rows and inserting into dtListB.Rows. It is increasing the Count and just looping for an indeterminate amount of time.

The problem is that you aren't really checking if StudentId of ListA doesn't exist in dtListB. What your code actually does is it compares EVERY element in dtListB with the current element from ListA and if in case they are not the same, it adds a new row to dtListB. So assume you have the following lists:
ListA = { 3, 4 };
dtListB = { 1, 2, 3 };
The first iteration for ListA, value is 3.
Check: (3 <> 1) and add '3' to dtListB (dtListB = { 1, 2, 3, 3 })
Check: (3 <> 2) and add '3' to dtListB (dtListB = { 1, 2, 3, 3, 3 })
Check: (3 <> 3) and don't do anything.
(Since the list has grown, you have two more iterations)
For the second iteration for ListA with value 4 you will insert it 5 times for every element of the existing array you compare with, and get the resulting list: { 1, 2, 3, 3, 3, 4, 4, 4, 4, 4 }. Obviously that's not the result you are expecting, and you probably have larger lists and run out of memory.
I would suggest keeping a Boolean flag itemFound when looping through dtListB. Set it to False before the loop and if a matching item is encountered, set it to True. After the loop, check if itemFound is False and if so, add the item to the list. This probably isn't valid VB syntax, but you get the idea:
For Each la In listA
stidListA = la.StudentId
Dim itemFound as Boolean = False
For n = 0 To dtListB.Rows.Count - 1 Step 1
stIdListB = dtListB.Rows(n)("StudentId")
If stIdListB <> stidListA Then
itemFound = True
Break //(is there Break in VB?)
End If
Next
If Not itemFound Then
dtListB.Rows.Add(New Object() {la.StudentId, la.AssignedId, la.TimeSheetId, 0})
End If
Next

Related

Is there a way to sort a list of numbers whilst maintaining their original indexes in VB.net?

I need to sort a list of numbers but I need to keep their initial indexes.
I had previously just created an array of the numbers and then another array of the indexes which I sorted at the same time like so:
Dim AverageSuccess(23) As Decimal
Dim intervalList() As Integer = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}
x = 2
Do
Sorted = True
For i = 23 To x Step -1
If AverageSuccess(i) < AverageSuccess(i - 1) Then
TempNum = AverageSuccess(i)
AverageSuccess(i) = AverageSuccess(i - 1)
AverageSuccess(i - 1) = TempNum
TempIndex = intervalList(i)
intervalList(i) = intervalList(i - 1)
intervalList(i - 1) = TempIndex
Sorted = False
End If
Next
x += 1
Loop Until Sorted
however this is for a project and my teacher informed me that this is bad programming practise and I should be using a list instead.
I have struggled to find a simple example of how to use a list in VB.net for this purpose, so if someone could give me an example I would appreciate it.
I don't know how much you have covered about lists in class...
Let us create a list with some integers in:
Dim nums As New List(Of Integer) From {9, 8, 4, 5}
Now, we want to store the original indices of those numbers. We can do that with the Select method, which has an optional parameter that will give the index of the current item, and create a new entity with items which we can give names to, say "Num" and "Idx":
Dim numsWithIndex = nums.Select(Function(n, i) New With {.Num = n, .Idx = i})
Then we can use the LINQ method OrderBy to get those entities in the desired order:
Dim sortedNums = numsWithIndex.OrderBy(Function(nwi) nwi.Num)
And we can have a look at what we have constructed with
Console.WriteLine(String.Join(vbCrLf, sortedNums))
which outputs:
{ Num = 4, Idx = 2 }
{ Num = 5, Idx = 3 }
{ Num = 8, Idx = 1 }
{ Num = 9, Idx = 0 }
(It shows the names we gave to the properties of the anonymous type created with New earlier.)
Here is the whole thing as a console app you can copy-and-paste to investigate with on your computer:
Module Module1
Sub Main()
Dim nums As New List(Of Integer) From {9, 8, 4, 5}
Dim numsWithIndex = nums.Select(Function(n, i) New With {.Num = n, .Idx = i})
Dim sortedNums = numsWithIndex.OrderBy(Function(nwi) nwi.Num)
Console.WriteLine(String.Join(vbCrLf, sortedNums))
Console.ReadLine()
End Sub
End Module

Im having problems figuring out how to print in an array

Not sure how to output the numbers, once they are in ascending order.
This is the task in the pseudocode that I am trying to move into VB.
Dim a() = {2,3,1,4}
Dim swapped = False
Output the values of a()
Do Swapped šŸ”Ø False
For I = 1 to end of the array Compare a(i-1) with a(i) if they are not in ascending order pass them to swapped (from task 1)
Swapped(a(i-1),a(i)) assign the returned value to the
variable swapped.
While swapped = True
Output the values of a()
Dim num = New Integer() {2, 3, 1, 4}
Dim swapped As Boolean = False
While swapped = False
For i = 1 To 4
If num(i - 1) > num(i) Then
temp = num(i)
num(i) = num(i - 1)
num(i - 1) = temp
swapped = True
Else
swapped = False
End If
Next
End While
While swapped = True
Console.WriteLine(num)
End While
Console.ReadLine()
Here you go:
For Each n As Integer In num
Console.WriteLine(n.ToString)
Next
Btw there's a problem with your swapping algorithm: if they are already in the right you will enter an infinite loop, and if there's a swap on the last number you'll exit the loop even if they are not in the right order. If it puzzles you let me a comment and we'll sort this out.
Although, #laancelot showed you how to output the array, I thought I would show you a simple way to sort an array.
Private Sub OrderArray()
Dim num As Integer() = {2, 3, 1, 4}
Array.Sort(num)
Console.WriteLine("Ascending")
For Each i In num
Console.WriteLine(i.ToString)
Next
'If you want it the other way around
Array.Reverse(num)
Console.WriteLine("Descending")
For Each i In num
Console.WriteLine(i.ToString)
Next
Console.ReadLine()
End Sub
If you don't want to use vb net generic array order method, and you prefer use the swap concept, here you can try:
Private Sub TestOrderSwap()
Dim num = New Integer() {9, 7, 0, 11, 12, 10, 6, 2, 3, 1, 4}
If OrderSwap(num, "ASC") Then
For a = 0 To num.Length - 1
Debug.Print(num(a))
Next
End If
If OrderSwap(num, "DESC") Then
For a = 0 To num.Length - 1
Debug.Print(num(a))
Next
End If
End Sub
Private Function OrderSwap(ByRef myArray As Integer(), OrderType As String) As Boolean
Dim swp As Integer = 0
Dim swpFlg As Boolean = False
For a = 1 To myArray.Length - 1
swp = myArray(a)
For b = 0 To a - 1
If (myArray(b) > swp And OrderType = "ASC") Or (myArray(b) < swp And OrderType = "DESC") Then
For c = a - 1 To b Step -1
myArray(c + 1) = myArray(c)
Next
myArray(b) = swp
swpFlg = True
Exit For
End If
Next
Next
Return swpFlg
End Function

vb.net array.sort() parameters why 1 short?

I'm sorting an array using code like this:
Array.Sort(arr, 0, intEndingPosition, New myIComparer)
I want the sorting to start with index 0 and end with index intEndingPosition. However, the last element arr(intEndingPosition) was left out and did not get sorted. Why?
intEndingPosition is calculated beforehand like this:
Dim StringOfConcern As String
Dim OneChar(65534), FrqOne(65534) As String
Dim CntNewOnes, CntRptOnes As Integer
Dim c As Char
Dim i, j As Integer
Dim isNew As Boolean
StringOfConcern = TextBox1.Text
OneChar(0) = CStr(StringOfConcern(0))
FrqOne(0) = 1
i = 0
j = 0
For Each c In StringOfConcern.Substring(1)
isNew = True
For j = 0 To i Step 1
If CStr(c) = OneChar(j) Then
isNew = False
FrqOne(j) += 1
Exit For
End If
Next j
If isNew = True Then
i += 1
OneChar(i) = CStr(c)
FrqOne(i) = 1
End If
Next c
CntNewOnes = i + 1
CntRptOnes = 0
For i = 0 To CntNewOnes - 1 Step 1
If FrqOne(i) > 1 Then CntRptOnes += 1
Next i
The sorting follows here. The code in my original question is only illustrative. The actual sorting is:
Array.Sort(FrqOne, OneChar, 0, CntNewOnes - 1)
Array.Reverse(FrqOne, 0, CntNewOnes - 1)
Array.Reverse(OneChar, 0, CntNewOnes - 1)
Note the method declaration for Array.Sort
Public Shared Sub Sort (
array As Array,
index As Integer,
length As Integer,
comparer As IComparer
)
The third parameter is the number of elements in the range to sort (length) not the end index as you suggest.
So let's assume for a minute that your intEndingPosition is 4. This means you're expecting to sort 5 elements i.e. elements at indices 0, 1, 2, 3, 4. However, the number 4 is the length and not the end index thus you're only sorting elements at indices 0, 1, 2, 3.
This explains why you're observing that the elements being sorted is one shorter than you expected.
Put it simply the third parameter should specify the length of elements to sort and not the end index.
Another Example:
Consider the Substring method of the String class:
Public Function Substring (
startIndex As Integer,
length As Integer
) As String
Then assume we have this piece of code:
Dim temp As String = "testing"
Dim result As String = temp.Substring(0, 4)
result is now a string containing 4 characters as 4 in the Substring call indicates the length that should be retrieved as opposed to the end index.
Had 4 been the end index then you'd expect result to contain 5 characters.

Unique Combination of Set

I'm trying to write vb.net code to return unique combinations for set
My set contains 3 different elements. I've found similar post this Post but couldn't find any VB solution to get this results
Example:
Elements: 1, 2, 3
{ 1, 2, 3}
Result must be
1
2
3
12
13
23
123
...........
>...................
i,m trying to achieve this by using following code
Function GetCombinations(ByVal depth As Integer, ByVal values As String()) As IEnumerable(Of String)
If depth > values.Count + 1 Then Return New List(Of String)
Dim result = New List(Of String)
For i = 0 To depth - 1
For y = 0 To values.Count - 1
If i = 0 Then
result.Add(values(y))
Else
result.Add(values(i - 1) + values(y))
End If
Next
Next
Return result
End Function
To Get the result
Dim reslt = GetCombinations(4, data_array)
?reslt
Count = 12
(0): "1"
(1): "2"
(2): "3"
(3): "11"
(4): "12"
(5): "13"
(6): "21"
(7): "22"
(8): "23"
(9): "31"
(10): "32"
(11): "33"
Hint:
I work with Mathematics and manage to calculate no of combinations. i can test the out with
this formula
Example
there is this formula called nCr. it means out of n number of element how many way of taking r number of elements with unique combinations of r.
nPr = n!/(n-r)!
n! = 1 * 2 * 3 * 4* ... (n-1) * n
Elements: 1, 2, 3
In this case n = 3 and r can be 1, 2, and 3 all
number of combinations = 3P1 + 3P2 + 3P3
= 3!/2! + 3!/1! + 3!/0!
= 6/2 + 6/1 + 6/1 (0!=1)
= 3+6+6
= 15
Knowing the term makes it easier to find existing algorithms. What you're looking for is a power set. Here's a quick VB.NET translation of a C# implementation I found on Rosetta Code:
Public Function GetPowerSet(Of T)(ByVal input As IEnumerable(Of T)) As IEnumerable(Of IEnumerable(Of T))
Dim seed As IEnumerable(Of IEnumerable(Of T)) = {Enumerable.Empty(Of T)()}
Return input.Aggregate(seed, Function(a, b) a.Concat(a.Select(Function(x) x.Concat({b}))))
End Function
Testing:
For Each x In GetPowerSet({1, 2, 3})
Console.WriteLine(String.Join(", ", x))
Next
Output:
1
2
1, 2
3
1, 3
2, 3
1, 2, 3
EDIT - Based on your latest explanation, I think you need a different approach. It seems you want combinations with repetitions / replacement, for all sizes up to the input size. You could simply call one of those algorithms with parameters (S, k) for each value of k from 1 to n and join all the results into a single set of results.
Translating Python's algorithm:
Public Iterator Function GetCombinationsWithReplacement(Of T)(source As IEnumerable(Of T), size As Integer) As IEnumerable(Of IEnumerable(Of T))
Dim pool = source.ToList()
Dim n = pool.Count
If n = 0 AndAlso size > 0 Then
Return
End If
Dim indices = Enumerable.Repeat(0, size).ToList()
Yield indices.Select(Function(i) pool.Item(i))
While True
Dim index As Nullable(Of Integer) = Nothing
For i = size - 1 To 0 Step -1
If indices.Item(i) <> n - 1 Then
index = i
Exit For
End If
Next
If Not index.HasValue Then
Return
End If
indices = indices.Take(index.Value).Concat(Enumerable.Repeat(indices.Item(index.Value) + 1, size - index.Value)).ToList()
Yield indices.Select(Function(i) pool.Item(i))
End While
End Function
(You will need to modify this if your VB.NET compiler doesn't support Yield.)
The results of calling this with different sizes are:
GetCombinationsWithReplacement({1, 2, 3}, 1):
{1}
{2}
{3}
GetCombinationsWithReplacement({1, 2, 3}, 2):
{1, 1}
{1, 2}
{1, 3}
{2, 2}
{2, 3}
{3, 3}
GetCombinationsWithReplacement({1, 2, 3}, 3):
{1, 1, 1}
{1, 1, 2}
{1, 1, 3}
{1, 2, 2}
{1, 2, 3}
{1, 3, 3}
{2, 2, 2}
{2, 2, 3}
{2, 3, 3}
{3, 3, 3}
We can join these into a single sequence with all 19 subsets:
Public Iterator Function GetCombinationsWithReplacementAllSizes(Of T)(source As IEnumerable(Of T)) As IEnumerable(Of IEnumerable(Of T))
Dim pool = source.ToList()
For size = 1 To pool.Count
For Each subset In GetCombinationsWithReplacement(pool, size)
Yield subset
Next
Next
End Function
Here is some pseudo code for any number of elements to help you (I make no claim this is the fastest way to do this, it is just a way to do it.)
Given elementList is a list of elements given
Given tempList is a list as a temporary holder
Given resultList is a list of the result
loop by # items in elementlist
{
if tempList is empty // special case for first iteration
add each element of elementList to tempList and resultlist
else
{
for each element in templist
for each element2 in elementlist
add combo to result list
copy elements added to result list for this iteration to templist
}
}

How to iterate a jagged array?

This has been driving me crazy for a few days. Why doesn't the following work?
Dim arr(3, 3) As Integer
For y As Integer = 0 To arr.GetLength(0) - 1
For x As Integer = 0 To arr.GetLength(y) - 1
arr(y, x) = y + x
Next
Next
Also, what if the array looked like this instead?
{ {1, 2, 3},
{4, 5, 6, 7, 8, 9, 9, 9},
{5, 4, 3, 2}
}
Because there is no '2' or '3' dimension. Should be .GetLength(1) instead of .GetLength(y)
Also: in VB.Net array declarations work a little differently. The subscript you specify in the declaration is the last index, not the number of items created like with C# or C++. But the array is still 0-indexed like C# or C++, instead of 1-indexed like VB6. That means that if you move to VB.Net from a different language your array instincts are probably wrong, no matter which language it is. In VB.Net, Dim arr(3,3) As Integer actually creates a 4x4 array.
Ok, so what you really need is a "jagged array". This will allow you to have an "array that contains other arrays of varying lengths".
Dim arr As Integer()() = {New Integer() {1, 2, 3}, New Integer() {4, 5, 6, 7, 8, 9, 9, 9}, New Integer() {5, 4, 3, 2}}
For x = 0 To arr.GetUpperBound(0)
Console.WriteLine("Row " & x & " has " & arr(x).GetUpperBound(0) & " columns")
For y = 0 To arr(x).GetUpperBound(0)
Console.WriteLine("(" & x & "," & y & ") = " & arr(x)(y))
Next
Next
Output:
Row 0 has 2 columns
(0,0) = 1
(0,1) = 2
(0,2) = 3
Row 1 has 7 columns
(1,0) = 4
(1,1) = 5
(1,2) = 6
(1,3) = 7
(1,4) = 8
(1,5) = 9
(1,6) = 9
(1,7) = 9
Row 2 has 3 columns
(2,0) = 5
(2,1) = 4
(2,2) = 3
(2,3) = 2
arr.GetLength(y)
should be
arr.GetLength(1)
Well what if I had an array that looked like this
{ {1, 2, 3},
{4, 5, 6, 7, 8, 9, 9, 9},
{5, 4, 3, 2}
}
How would GetLength(1) still know the length of each row?
Basically what I want is.... a way to find the number of elements in any given row.
Dim arr(3, 3) As Integer
Dim y As Integer
Dim x As Integer
For x = 0 To arr.Rank - 1
For y = 0 To arr.GetLength(x) - 2
arr(x, y) = x + y
Next
Next
The above code worked for me.
Edit, the code feels dirty though. I'm wondering what it is you are trying to accomplish?
Your declaration: DIM arr(3,3) As Integer allready specifies that there are 3 elements in any given row (or 4, I'm not so sure about VB)
You could try:
Dim arr(3) as Integer()
You should then be able to do:
arr(n).Length
To find the length of row n.
I'm a bit rusty on VB6 and never learned VB.NET, but this should give you a 'jagged' array. Check out the msdn documentation on multidimensioned arrays.
This code en C# is to get all the combinations of items in a jagged array:
static void Main(string[] args)
{
bool exit = false;
int[] indices = new int[3] { 0, 0, 0 };
string[][] vectores = new string[3][];
vectores[0] = new string[] { "A", "B", "C" };
vectores[1] = new string[] { "A", "B" };
vectores[2] = new string[] { "B", "D", "E", "F" };
string[] item;
int[] tamaƱos = new int[3]{vectores[0].GetUpperBound(0),
vectores[1].GetUpperBound(0),
vectores[2].GetUpperBound(0)};
while (!exit)
{
item = new string[]{ vectores[0][indices[0]],
vectores[1][indices[1]],
vectores[2][indices[2]]};
Console.WriteLine("[{0},{1},{2}]={3}{4}{5}", indices[0], indices[1], indices[2], item[0], item[1], item[2]);
GetVector(tamaƱos, ref indices, ref exit);
}
Console.ReadKey();
}
public static void GetVector(int[] tamaƱos, ref int[] indices, ref bool exit)
{
for (int i = tamaƱos.GetUpperBound(0); i >= 0; i--)
{
if (tamaƱos[i] > indices[i])
{
indices[i]++;
break;
}
else
{
//ULTIMO ITEM EN EL ARRAY, VALIDAR LAS OTRAS DIMENSIONES SI YA ESTA EN EL ULTIMO ITEM
if (!ValidateIndexes(tamaƱos, indices))
indices[i] = 0;
else
{
exit = true;
break;
}
}
}
}
public static bool ValidateIndexes(int[] tamaƱos, int[] indices)
{
for (int i = 0; i < tamaƱos.Length; i++)
{
if (tamaƱos[i] != indices[i])
return false;
}
return true;
}
The output looks like
[0,0,0]=AAB
[0,0,1]=AAD
[0,0,2]=AAE
[0,0,3]=AAF
[0,1,0]=ABB
[0,1,1]=ABD
[0,1,2]=ABE
[0,1,3]=ABF
[1,0,0]=BAB
[1,0,1]=BAD
[1,0,2]=BAE
[1,0,3]=BAF
[1,1,0]=BBB
[1,1,1]=BBD
[1,1,2]=BBE
[1,1,3]=BBF
[2,0,0]=CAB
[2,0,1]=CAD
[2,0,2]=CAE
[2,0,3]=CAF
[2,1,0]=CBB
[2,1,1]=CBD
[2,1,2]=CBE
[2,1,3]=CBF