Related
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
Dim LastNumber as Integer = 1
Dim num_0() as Integer = {1, 2, 3, 4, 5}
Dim num_1() as Integer = {6, 7, 8, 9, 10}
Dim num_2() as Integer = {20, 21, 14, 36, 0}
Dim y() As Integer
y(0) = num_0(2)
When I use this code it executes perfectly
But the problem is I want to change the "0" in num_0(2)
When I do...
y(0) = num_ & LastNumber & (2)
This doesnt work
Or
y(0) = ("num_" & LastNumber & "(2)")
This gives me an error that converting a string to an integer is not possible
My question is How can I replace the "0" in num_0(2) with the LastNumber integer variable... so it reads the "8" out of the array num_1(2)
You can use multidimensional array (AKA rectangular array):
Dim num As Integer(,) = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {20, 21, 14, 36, 0} }
y(0) = num(LastNumber, 2)
or jagged array (array of arrays) :
Dim num As Integer()() = { ({1, 2, 3, 4, 5}), ({6, 7, 8, 9, 10}), ({20, 21, 14, 36, 0}) }
y(0) = num(LastNumber)(2)
I have a byte array of data. How can I find and replacement a part of the byte array with replacement data?
dim foo as byte
foo = MY DATA
If foo was a string, then I would do:
foo = replace( foo, target, replacement )
But foo is a byte array. How can I replace?
Just for the fun of it, here is an implementation:
<TestMethod()>
Public Sub Test_ArrayReplace()
AssertEqualArray({1, 4}, ArrayReplace({1, 2, 3}, {2, 3}, {4}))
AssertEqualArray({1, 4, 5}, ArrayReplace({1, 2, 3, 5}, {2, 3}, {4}))
AssertEqualArray({1, 4, 2}, ArrayReplace({1, 2, 3, 2}, {2, 3}, {4}))
AssertEqualArray({1, 4, 5, 2}, ArrayReplace({1, 2, 3, 2}, {2, 3}, {4, 5}))
AssertEqualArray({1, 2, 3, 8, 9}, ArrayReplace({1, 2, 3, 8, 2, 3, 4}, {2, 3, 4}, {9}))
AssertEqualArray({1, 68, 69, 70, 255}, ArrayReplace({1, 65, 66, 67, 255}, "ABC", "DEF", Encoding.ASCII))
End Sub
Private Sub AssertEqualArray(expected() As Byte, actual() As Byte)
Assert.IsNotNull(expected, "expected")
Assert.IsNotNull(actual, "actual")
Assert.AreEqual(expected.Length, actual.Length, "length")
For index = 0 To actual.Length - 1
Assert.AreEqual(expected(index), actual(index), String.Format("index: {0}", index))
Next
End Sub
Public Function ArrayReplace(data() As Byte, find As String, replacement As String, enc As Encoding) As Byte()
Return ArrayReplace(data, enc.GetBytes(find), enc.GetBytes(replacement))
End Function
Public Function ArrayReplace(data() As Byte, find() As Byte, replacement() As Byte) As Byte()
Dim matchStart As Integer = -1
Dim matchLength As Integer = 0
Using mem = New IO.MemoryStream
For index = 0 To data.Length - 1
If data(index) = find(matchLength) Then
If matchLength = 0 Then matchStart = index
matchLength += 1
If matchLength = find.Length Then
mem.Write(replacement, 0, replacement.Length)
matchLength = 0
End If
Else
If matchLength > 0 Then
mem.Write(data, matchStart, matchLength)
matchLength = 0
End If
mem.WriteByte(data(index))
End If
Next
If matchLength > 0 Then
mem.Write(data, data.Length - matchLength, matchLength)
End If
Dim retVal(mem.Length - 1) As Byte
mem.Position = 0
mem.Read(retVal, 0, retVal.Length)
Return retVal
End Using
End Function
The implementation is surely not perfect and might even be buggy.
Keep in mind that in order to convert a String into an ByteArray you have to know the Encoding of the String.
You can call it this way:
foo = ArrayReplace(foo, "find", "replace", Encoding.UTF8)
I have 3 x one dimensional arrays of type integer, each array is the same length (between 5 - 20 million values) and I would like to sort them in parallel (ie keeping the relative position) by the second array, then the third array, then the first array. Does anyone have any ideas on the most efficient way to do this in vb.net?
If it helps, the first array is just a record of the initial position (the three arrays will be re-sorted to this order once various calculations are done). I need to sort them to determine the number of unique combinations of the second and third arrays (a combination is determined by the position in the array - in the example below the combinations are (0-1-4), (1-1-6) etc). Once that is determined I will resort them back based on the first array.
I looked at array.sort but that only covers 2 parallel arrays. I'm a bit wary of putting the values in tuples (or any other format), as it would (I assume - perhaps not) be a big overhead when converting 5 - 20 million records before processing.
For example:
Record Number Array: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Link Array: {1, 1, 2, 1, 1, 2, 2, 2, 1, 2}
Line Number Array: {4, 6, 3, 5, 6, 7, 3, 2, 3, 4}
Having sorted / ordered by the second, then third, then first array, the expected output would be:
Record Number (1st Array): {8, 0, 3, 1, 4, 7, 2, 6, 9, 5}
Link Array (2nd Array): {1, 1, 1, 1, 1, 2, 2, 2, 2, 2}
Line Number Array (3rd Array): {3, 4, 5, 6, 6, 2, 3, 3, 4, 7}
Array.sort only allows you to sort 2 arrays in parallel and i'm a little confused by the options available in LinQ.
Does anyone have any suggestions on the best way to solve this problem?
Cheers,
I think you can get a backup of your Link Array. Then sort Link Array with Record Array, then you can sort un-sorted Link Array with Line Number Array. Can you please try it?
You didn't say if you want efficient in terms of time or space, but this takes about 3 seconds to transfer 20 million records from arrays to a list, and then about 30 seconds to do the sort on them, using less than 1GB of RAM. On my computer.
Option Infer On
Module Module1
Class Grouped
Property RecNo As Integer
Property Link As Integer
Property LineNo As Integer
Public Overrides Function ToString() As String
Return String.Format("({0}, {1}, {2})", Me.RecNo, Me.Link, Me.LineNo)
End Function
End Class
Sub Main()
' First try with the test data to show the correct result is obtained
Dim recNos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Dim links = {1, 1, 2, 1, 1, 2, 2, 2, 1, 2}
Dim lineNos = {4, 6, 3, 5, 6, 7, 3, 2, 3, 4}
' transfer the arrays to a List
Dim xs As New List(Of Grouped)
xs.Capacity = recNos.Length
For i = 0 To recNos.Length() - 1
xs.Add(New Grouped With {.RecNo = recNos(i), .Link = links(i), .LineNo = lineNos(i)})
Next
' sort the data
Dim ys = xs.OrderBy(Function(x) x.Link).ThenBy(Function(x) x.LineNo).ToList()
Console.WriteLine(String.Join(", ", ys))
' Now try with twenty million records
Dim rand = New Random()
Dim nRecs As Integer = 20000000
recNos = Enumerable.Range(0, nRecs - 1).ToArray()
ReDim links(nRecs - 1)
ReDim lineNos(nRecs - 1)
For i = 0 To nRecs - 1
links(i) = rand.Next(0, 9)
lineNos(i) = rand.Next(1, 9)
Next
Dim sw As New Stopwatch
sw.Start()
xs.Clear()
xs.Capacity = nRecs
For i = 0 To recNos.Length() - 1
xs.Add(New Grouped With {.RecNo = recNos(i), .Link = links(i), .LineNo = lineNos(i)})
Next
sw.Stop()
Console.WriteLine(sw.ElapsedMilliseconds.ToString())
sw.Restart()
ys = xs.OrderBy(Function(x) x.Link).ThenBy(Function(x) x.LineNo).ToList()
sw.Stop()
Console.WriteLine(sw.ElapsedMilliseconds.ToString())
Console.ReadLine()
End Sub
End Module
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