Find average of a specific number of rows/columns in VB.Net Datatable and store to array - database

I am trying to program a noise reduction algorithm that works with a set of datapoints in a VB.NET DataTable after being helped with my other question. Basically, I want to take two integers, a coordinate value (yCoord for example) and a threshold smoothing value (NoiseThresh), and take the average of the values in the range of (yCoord - NoiseThresh, yCoord + NoiseThresh) and store that number into an array. I'd repeat that process for each column (in this example) and end up with a one-dimensional array of average values. My questions are:
1) Did anything I just say make any sense ;), and
2) Can anyone help me with the code? I've got very little experience working with databases.
Thanks!
An example of what I'm trying to do:
//My data (pretend it's a database)
1 4 4 9 2 //yCoord would equal 5
6 3 8 12 3 //yCoord = 4
8 3 -2 2 0 //yCoord = 3
9 17 3 7 5 //yCoord = 2
4 1 0 9 7 //yCoord = 1
//In this example, my yCoord will equal 3 and NoiseThresh = 1
//For the first column
Array(column1) = //average of the set of numbers centered at yCoord = 3 _
//(in this case 8) and the NoiseThresh=1 number on either side (here 6 & 9)
//For the second column
Array(column2) = //average of the numbers 3,3,17 for example
//etc., etc.,
This would be performed on a large data set (typical numbers would be yCoord=500, NoiseThresh = 50, Array length = 1092) so there is no possibility of manually entering the numbers.
I hope this helps clarify my question!
P.S.: yes, I know that // isn't a VB.NET comment.

I must admit that i've yet not understood the range part (NoiseThresh etc.), but this is a start:
Dim averages = (From col In tbl.Columns.Cast(Of DataColumn)()
Select tbl.AsEnumerable().
Average(Function(r) r.Field(Of Int32)(col.ColumnName))).
ToArray()
It calculates every average of each column in the DataTable and creates a Double() from the result (average can result in decimal places even if used on integers).
Edit: With your example i've now understood the range part. So basically yCord is the row-index(+1) and noiseThreas is the row-range (+/- n rows).
Then this gives you the correct result(made some code comments):
Dim yCord = 2 ' the row index(-1 since indices are 0-based) '
Dim noiseThresh = 1 ' +/- row '
' reverse all rows since your sample begins with index=5 and ends with index=1 '
Dim AVGs As Double() = (
From colIndex In Enumerable.Range(0, tbl.Columns.Count)
Select tbl.AsEnumerable().Reverse().
Where(Function(r, index) index >= yCord - noiseThresh _
AndAlso index <= yCord + noiseThresh).
Average(Function(r) r.Field(Of Int32)(colIndex))).ToArray()
The most important part of this this LINQ query is the Where. It applies your range on the IEnumerable(of DataRow). Then i'm calculating the average of these rows for every column. The last step is materializing the query to a Double().
Result:
(0) 7.666666666666667 Double => (6+8+9)/3
(1) 7.666666666666667 Double => (3+3+17)/3
(2) 3.0 Double => (8-2+3)/3
(3) 7.0 Double => (12+2+7)/3
(4) 2.6666666666666665 Double => (3+0+5)/3
Edit2:
One last thing. I assume that to do the same for the other axis I just
switch x & y and row & column?
It's not that simple. But have a look yourself:
Dim noiseThresh = 1 ' +/- column '
Dim xCord = 2 ' the column index(-1 since indices are 0-based) '
' assuming that your x-cords now start with index=0 and ends with tbl.Column.Count-1 '
Dim AVGs As Double() = (
From rowIndex In Enumerable.Range(0, tbl.Rows.Count)
Select tbl.Columns.Cast(Of DataColumn)().
Where(Function(c, colIndex) colIndex >= xCord - noiseThresh _
AndAlso colIndex <= xCord + noiseThresh).
Average(Function(c) tbl.Rows(rowIndex).Field(Of Int32)(c.Ordinal))).ToArray()
Result:
(0) 5.666666666666667 Double => (4+4+9)/3
(1) 7.666666666666667 Double => (3+8+12)/3
(2) 1.0 Double => (3-2+2)/3
(3) 9.0 Double => (17+3+7)/3
(4) 3.3333333333333335 Double => (1+0+9)/3

Related

Effectively using 2D VBA Array variable and fetch whenever required

I am trying to develop a mechanism where I can store all the values in 2D array for below table.
Below is the code that I have developed, just to store values.
Sub temp()
Dim QtyArray(4, 11) As Integer, rw As Integer, col As Integer
For rw = 0 To 4
For col = 0 To 11
QtyArray(rw, col) = Cells(rw + 2, col + 3).Value
MsgBox QtyArray(rw, col)
Next col
Next rw
End Sub
I want to apply logic as per below:
First identify columns where COUNTA is 1 (highlighted in red) and move 1 qty of stock from that store to another store where COUNTA > 2, priority would be in order from store A to L. For example, first store with COUNTA=1 is store D, and it has qty 2. So I want to move these 2 qty to store E (not store C because it has already 1 qty, also H has 2 qty.)
If the COUNTA of any store's qty is zero, nothing to be done.
I want to fetch separate report as per below format, showing how the stock is being moved across store as per logic rule 1.
Output:
Explained in previous section.

Split a array in VBA and output to multiple columns in Excel

I have a long array that exceeds the maximum number of rows of a single column (1048576), and I wish to output this array into multiple columns, for example, if my array length is 3145728, and so I intend to create 3 separate arrays, each with length 1048576, so 1 to 1048576 would be output to column A, 1048577 to 2097152 to column B, and 2097153 to 3145728 to column C. My code attempted is as follows:
Sub test()
'for simplicity, just created a simply long array
Dim arrIn(1 To 3145728, 1 To 1) As Long
For i = 1 To 3145728
arrIn(i, 1) = i
Next i
'created 3 separate arrays, each with length of 1048576
Dim arrOut1(1 To 1048576, 1 To 1) As Long, arrOut2(1 To 1048576, 1 To 1) As Long, arrOut3(1 To 1048576, 1 To 1) As Long
Dim p As Long, p2 As Long, p3 As Long
'because counter p is going to be from 1 to 3145728, for the second and third arrays, the counter need to restart from 1 and upto 1048576
p2 = 1
p3 = 1
For p = 1 To 3145728
Select Case p
Case Is <= 1048576
arrOut1(p, 1) = arrIn(p, 1)
Case Is <= 2097152
arrOut2(p2, 1) = arrIn(p, 1)
p2 = p2 + 1
Case Is <= 3145728
arrOut3(p3, 1) = arrIn(p, 1)
p3 = p3 + 1
End Select
Next p
Range("A1:A1048576") = arrOut1
Range("B1048577: B2097152") = arrOut2
Range("C2097153:C3145728") = arrOut3
End Sub
The first column (arrOut1) was output to column A, however, when it comes to the second column (arrOut2), VBA returns Run-time error '1004': Menthod 'Range' of object '_Global' failed.
I checked the locals windows results, p2 and p3 were 1048577, and arrOut2(1,1) = 1048577, arrOut2(1,1) = 1048578, and so on, seems the arrays all get populated, however I'm not sure what is prohibiting them from being spitted out to the columns. Thank you for your advice.
Ok so, just realized that Range(“B1048577:B...) was nonsense... so it is solved. Thank you!

VBA create loop for column B based on value in column A

I have a code that does what I need. The problem is I have to do the range select manually I'd like to create a conditional loop.
Here's my code that I used so far
Sub Worksheet_functions()
Dim Sumtotal As Long
Sumtotal = WorksheetFunction.Sum(Selection)
Range("e2").Value = Sumtotal
Range("h2").Value = Range("e2") + Range("h2")
End Sub
This is what my data looks like
Price Volume E H
10 100
10 50
10 80
9 100
9 50
8 100
8 100
10 50
10 250
At the moment I'm manually selection the volume column from the top down based on the value in price column.
The conditions are
If The prices are the same continue selecting them until they are not
If the price goes down then those selected cells should be summed in e4 and added to h4
If the price goes up then those selected cells should be summed in e2 and added to h4
For my example this would look like:
( H2: 100+50+80 +50+250 = 530 )
( H4: 100+50 +100+100 = 350 )
Price Volume
( 10 100
100+50+80 < ( 10 50
( 10 80
Above volume to H2
(9 100
100+50 < (9 50
Above volume to H4 ( because 10>9)
(8 100
100+100 < (8 100
Above volume to H4 ( because 9>8)
(10 50
50+250 < (10 250
Above volume to H2 ( because 8<10)
Any suggestions on
How do I use the conditions to make it loop?
How do write a code that takes in consideration the last price?
Here's a way to get what you want.
It is much difficult to create loop and Nested If's to do this.
I let Excel do the job and used Formula instead.
Let say your data is in A1:B10.
In E2 type this in formula bar.
=IF(A2=A3,IF(ISNUMBER(A1),IF(A1<A2,1,IF(A1=A2,E1,0)),1),IF(ISNUMBER(A1),IF(A1<A2,1,IF(A1=A2,E1,0)),1))
Copy the formula all the way down until E10 or up to where you have data.
In H2, type this in formula bar:
=SUMIF(E:E,1,B:B)
Similarly in H4, type this in formula bar:
=SUMIF(E:E,0,B:B)
However, you want code in VBA which is below also using above formula:
Dim ws as Worksheet, lrow as long
Set ws = Thisworkbook.Sheets("Sheet1")'assuming your data is in Sheet1
With ws
lrow = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("E2:E" & lrow).Formula = "=IF(A2=A3,IF(ISNUMBER(A1),IF(A1<A2,1,IF(A1=A2,E1,0)),1),IF(ISNUMBER(A1),IF(A1<A2,1,IF(A1=A2,E1,0)),1))"
.Range("E2:E" & lrow).Value = .Range("E2:E" & lrow).Value
.Range("H2").Formula = "=SUMIF(E:E,1,B:B)"
.Range("H2").Value = .Range("H2").Value
.Range("H4").Formula = "=SUMIF(E:E,0,B:B)"
.Range("H4").Value = .Range("H4").Value
End With
End Sub
Kinda late, but I hope this is what you want.

Truly drawing cards at random, and not just a random group? visual basic 2010

I realized a flaw on my coding for picking cards from my structure group arrays this morning for a tabletop card game I'm converting to computer.
Currently the code is set up to randomly pick an array of a specific card, but if quantity of cards in the group is < 1, then the group is skipped. For my deck this isn't being truly random because each card has its own quantity. Some cards have 10 cards, others 6, most 4. How can I code it to where it looks at all these quantity numbers as a whole and picks a random card out of these numbers.
If GameSize >= 3 Then
For StartHands = 10 To 14
Number = (DeckGroup(Rnd.Next(0, DeckGroup.Count)).ID)
'Cardslots Player3
If CardTypeArray(StartHands) = "" Then
If DeckGroup(Number).QuantityInteger > 0 Then
DeckGroup(Number).QuantityInteger -= 1
Player1HandGroup(Number).QuantityInteger3 += 1
CardTypeArray(StartHands) = Player1HandGroup(Number).CardType
Me.NumberArray(StartHands) = Number
Else
'Recall Procedure if Generated Random Number is not allowed
'due to QuantityInteger <= 0
Call StartButton_Click(sender, e)
End If
End If
Next StartHands
End If
when playing a card, and drawing a new card, I use this coding scheme, to prevent stackoverflow, but is virtual the same.
Dim temp As IEnumerable(Of LunchMoneyGame.LunchMoneyMainForm.Group) = From r In DeckGroup Where r.QuantityInteger > 0 Select r
If temp IsNot Nothing AndAlso temp.count > 0 Then
Number = (temp(Rnd.Next(0, temp.Count)).ID)
DeckGroup(Number).QuantityInteger -= 1
'Select the Player depending value of T
Select Case T
Case 0
Player1HandGroup(Number).QuantityInteger += 1
Case 1
Player1HandGroup(Number).QuantityInteger2 += 1
Case 2
Player1HandGroup(Number).QuantityInteger3 += 1
Case 3
Player1HandGroup(Number).QuantityInteger4 += 1
Case 4
Player1HandGroup(Number).QuantityInteger5 += 1
End Select
Edit:
Improved question:
How can I weight the probably of drawing a card based on how many of a particular card are left in the decks quantity integer for each card?
The idea of my solution is to generate a random number over the total number of availables cards in all deck groups. Finally we find the deck group this number targets within a loop:
Dim totalNumerOfCards As Integer = DeckGroup.Sum(Function(d) d.QuantityInteger)
Dim Number As Integer = Rnd.Next(totalNumerOfCards)
Dim numCards As Integer = 0
Dim groupIndex As Integer = 0
Dim cardIndex As Integer = 0
Dim i As Integer = 0
While i < DeckGroup.Length AndAlso numCards <= Number
groupIndex = i
cardIndex = Number - numCards
numCards += DeckGroup(i).QuantityInteger
i += 1
End While
Console.WriteLine("Your card is in DeckGroup({0}), card index {1}",
groupIndex, cardIndex);

Loop in Excel VBA

I have a logic in place, but no idea as to how to execute/code it in Excel. The logic is below:
At office, I need to find out the value of many old articles based on their purchase value and age. I don't want to use VDB or other inbuilt functions.
In my spreadsheet:
A1 = "Table" (Name of the article)
B1 = "01/01/2005" (Date of purchase in MM/DD/YYYY format)
C1 = "1000" (Purchase value)
D1 = "=DATEDIF(B1,TODAY(),"Y")" (Gives the age of article in years)
E1 = "20" (Percentage depreciation for first year, which varies based on article)
F1 = "=C1*10%" '(Depreciated value should not be less than 10% of purchase value)
Now, in G1 I want to calculate the depreciation value of article "A1" with purchase value "C1" for "D1" number of years, # flat "E1"% for first year and 10% for subsequent years.
H1 = "=C1-G1" (Value of the article after depreciation)
I1 = "=IF(H1<=F1,F1,H1)"
Please help me with a macro or formula to loop and find out the value of G1.
Also, I want to apply this to "n" number of rows since there are "n" number of articles.
EDIT
#assylias Thanks for enlightening me about SO policy, putting me to work for myself to find the answer.
After some 30 min of googling followed by trial and error, I successfully wrote a macro to do what I wanted. Here it goes:
Sub DepVal()
'
' DepVal Macro
' Macro by Prashanth JC
'
' Keyboard Shortcut: Ctrl+d
'
fYear = 0
dVal = 0
tYear = ActiveCell.Offset(0, -3)
purVal = ActiveCell.Offset(0, -4)
depFirst = ActiveCell.Offset(0, -2)
depOther = 10
If tYear >= 1 Then
Do
If fYear = 0 Then
dVal = purVal - (purVal * depFirst) / 100
Else
dVal = dVal - (dVal * depOther) / 100
End If
fYear = fYear + 1
Loop Until fYear = tYear
ActiveCell.Value = dVal
Else
ActiveCell.Value = purVal
End If
End Sub
Finally, I formatted the G1 cell to a Number with Zero decimal place. Everything works perfect now!
Thanks again, SO and assylias!
You don't need a macro, it's simple math.
Assuming that your percentage (in E1) is stored as .2 (for 20%), not actually 20, this formula would work:
=MAX(F1,C1*(1-E1)-(C1*0.1*(D1-1)))

Resources