How can I add something to an array and move everything down? - arrays

I'm trying to add a score to an array and check if that score is higher than the rest, and put it in the correct position and move everything else down. I have a 2-dimensional array highScores(9, 1), where the first part is each score, and the second part is the name when 0 and the score when 1. I want to be able to check where the new score should be entered and then move everything down if need be.
This is what I have so far, and it doesn't work.
Sub AddScore(name As String, score As String)
For i = 9 To 0 Step -1
If score > highScores(i, 1) Then
For j = i To 1 Step -1
highScores(j - 1, 0) = highScores(j, 0)
highScores(j - 1, 1) = highScores(j, 1)
Next
highScores(i, 0) = name
highScores(i, 1) = score
Exit For
End If
Next
End Sub

I'm guessing that the score at element 9 is the highest score and the score at element 0 is the lowest.
You were close, but not quite there. For a start, you should never do mathematical comparisons on strings. You should convert the strings to numeric values. For this there are several ways, but for you the simplest is to use the Val function.
Next. Have a think about what you're trying to achieve. Iterate through the scores from lowest to highest checking the score to see if it is higher than any in the array. If it is, move each high score down to the next element. A key thing here is to remember that element 0 has nowhere to go, it just gets overwritten by the one above. So start going along the array from element 1 to element i where you will be placing the new score. For example element 1 overwrites element 0, element 2 overwrites element 1 and so on. When this is done, you simply overwrite element i with the new values.
Finally, rather than use Exit For, use Exit Sub to leave that sub entirely. Exit For will only leave the inner For..Next loop and will then try to continue the outer loop.
Private Sub AddScore(name As String, score As String)
For i As Integer = 9 To 0 Step -1
If Val(score) > Val(highScores(i, 1)) Then
For j As Integer = 1 To i
highScores(j - 1, 0) = highScores(j, 0)
highScores(j - 1, 1) = highScores(j, 1)
Next
highScores(i, 0) = name
highScores(i, 1) = score
Exit Sub
End If
Next
End Sub

Related

Displaying some values from an array VBA excel

I'm trying to display multiple values on my excel file based on first line and first column. I've made a 2D array for my values. MyValue is an InputBox variable and I loop over the first column trying to find MyValue and I want to get on display values that are on "PSC", "BCCH" and so on columns, basically the same thing as a filter based on 1st column but displaying only some values from other columns. The output that i have for this operation is in this image:
However 136, 144 and 152 which are PSC values are on line 2, 3, 4 in my source excel file, I'm not sure what are those zeros. I want to diplay those values one under each other, I tried without offset method but if I don't use it I get no value displayed.
Dim1 = wSht.Range("A2", wSht.Range("A1").End(xlDown)).Cells.Count
Dim2 = wSht.Range("A1", wSht.Range("A1").End(xlToRight)).Cells.Count
For i = 1 To Dim1
For j = 1 To Dim2
If wSht.Cells(i, 1) = MyValue Then
If wSht.Cells(1, j) = "PSC" Then
ReDim Preserve Matrice(0 To 5, 0 To Matrice_size)
Matrice(0, Matrice_size) = wSht.Cells(i, j).value
Matrice_size = Matrice_size + 1
End If
If wSht.Cells(1, j) = "BCCH" Then
ReDim Preserve Matrice(0 To 5, 0 To Matrice_size)
Matrice(1, Matrice_size) = wSht.Cells(i, j).value
Matrice_size = Matrice_size + 1
End If
End If
Next j
Next i
For k = LBound(Matrice, 1) To UBound(Matrice, 1)
For l = LBound(Matrice, 2) To UBound(Matrice, 2)
ThisWorkbook.Worksheets(1).Range("A2").Offset(k, l).value = Application.Transpose(Matrice(k, l))
Next l
Next k
switch the first If line with the For j and also the corresponding last End If with the Next j, so the inner loop only runs through the correct rows.
it seems the data starts at line 2, so start the For i loop with 2.
if you only need data from those two columns you can look for them in a separate loop first and save their position, so you don't need a nested loop. (in this case my first point doesn't apply).
you don't even need a loop, you can use Excel's MATCH function.
the matrix and transpose seems to be an overkill. since i determines k and l you can get rid of this part, and write to Worksheets(1) directly from the i-j loop.
you have five rows in the matrix and every fifth output is a correct value, isn't that suspicious?
you seem to put values into line 0 and 1 of the matrix then read from line 1 and 2. this might be the reason for the line full of 0s
if you can provide what exactly you would expect from what exact source data, I can help you more. but without knowing, my solution would look something like
PSC_col = Application.WorksheetFunction.Match("PSC", wSht.Rows(1).EntireRow, 0)
BCCH_col = Application.WorksheetFunction.Match("BCCH", wSht.Rows(1).EntireRow, 0)
For i = 2 To wSht.[A2].End(xlDown).Row
If wSht.Cells(i, 1) = MyValue Then
ThisWorkbook.Worksheets(1).[A2].Offset(k, 0).Value = wSht.Cells(i, PSC_col).Value
ThisWorkbook.Worksheets(1).[B2].Offset(k, 0).Value = wSht.Cells(i, BCCH_col).Value
k = k + 1
End If
Next i

MATLAB: signal clipping method skips array indexes?

The problem: I have roughly isolated data points of the baselines either side of a square pulse signal. I now want to clip these arrays of data points from the 'pulse end' to their respective means (because I still have some data points from the rise and fall of the signal).
As you can see my method appears to work when starting at the end of an array and clipping backwards, but seems to skip data points when assessing array indexes starting from the beginning of the array.
The code:
baseline1=[1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,3,4;1:18];
baseline2=[4,3,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1;32:49];
%---------------------------------------------------
figure()
hold on
plot(baseline1(2,:),baseline1(1,:),'k')
plot(baseline2(2,:),baseline2(1,:),'k')
%---------------------------------------------------
%Clip baseline1
arrayMean = mean(baseline1(1,:));
x=size(baseline1,2);
meanCrossed = 0;
arrayClipped = baseline1;
for i=x:-1:1
if baseline1(1,i)>arrayMean && meanCrossed == 0
arrayClipped(:,i)=[];
else
meanCrossed = 1;
end
end
baseline1=arrayClipped;
%---------------------------------------------------
%Clip baseline2
arrayMean = mean(baseline2(1,:));
x=size(baseline2,2);
meanCrossed = 0;
arrayClipped = baseline2;
for i=1:x
if baseline2(1,i)>arrayMean && meanCrossed == 0
arrayClipped(:,i)=[];
else
meanCrossed = 1;
end
end
baseline2=arrayClipped;
%---------------------------------------------------
plot(baseline1(2,:),baseline1(1,:),'g','LineWidth',2)
plot(baseline2(2,:),baseline2(1,:),'g','LineWidth',2)
Can anyone advise?
Say you want to delete indices 4 then 2 from a vector of size 4. 4 goes away, so now it's size 3. 2 goes away, making it size 2:
1 2 3 4
1 2 3
1 3
Now say you want to delete indices 2 then 4. 2 goes away, so now it's size 3. Now we delete index 4.... WAIT A SECOND!
1 2 3 4
1 3 4
Index 4 doesn't exist, because we shortened the array. The element formerly known as the 4th element is now at index 3.
By deleting elements, you're changing the indexing of all elements from that point forward. Solution: save all the indices as you compute, and delete them all afterwards:
for ...
clipped_indices(end+1) = i;
end
arrayClipped(:, clipped_indices) = [];
Or, for a cleaner and faster implementation, don't make arrayClipped at all. Instead, make an logical array of all ones of the correct size, and zero them as you find the elements to clip, then index baseline2 with the resulting logical array at the end.
My working solution inspired by the answer:
%Data points on the rise and fall of the square wave are recursively clipped to the
%baseline of their respective arrays. With each loop the mean is reassessed
%and the end of the array clipped to the new mean.
%Clip baseline1
sizeStable = 0; %set flag
while sizeStable == 0
arrayMean = mean(baseline1(1,:)); %(re)calculate mean
x=size(baseline1,2); %(re)calculate size
meanCrossed = 0; %(re)set
for i=x:-1:1 %from x to 1 in steps of -1
if baseline1(1,i)>arrayMean && meanCrossed == 0 %if the data point is greater than the mean and the mean has not been crossed before
baseline1(:,i)=0; %make the entire column at that index zero
else
meanCrossed = 1;
end
end
baseline1( :, ~any(baseline1,1) ) = []; %delete columns with zeros
if size(baseline1,2) == x
sizeStable = 1;
end
end

How would I loop through an array and find any combination of numbers that adds up to equal a target number?

I have thought about this issue a lot, and I have found a way to do it, but there has to be a better way. I want to enter a target number, then loop through an array and find any possible combination of numbers that adds up to equal that target number.
For example, I know this code works to find all combinations of two numbers that add up to equal the target number:
For i as Integer = 0 To MyArray.Length - 1
For j as Integer = (i + 1) To MyArray.Length - 1
If(MyArray(i) + MyArray(j)) = TargetNumber Then
'Output these two numbers
EndIf
Next
Next
As you can see, this algorithm is designed only to get combinations of two numbers that add up to equal the target number. I know that I could nest another For loop (or as many as I want) to find as many numbers as I want to find, but there has to be a better, more efficient way. I don't want to have to nest another loop every time I want to find another number. Any suggestions? Should I avoid using arrays and try some other approach? Any help is appreciated.
This wont repeat any number in the BasicNums array, and it means that only specified number can print out the number combination.
Code below:
Module Module1
Dim BasicNums() As Integer = {1, 2, 3, 4, 5, 6, 7, 8}
Dim nums As New List(Of Integer)
Dim TargetNumber As Integer
Sub Main()
TargetNumber = Console.ReadLine()
Recursion(0, 0, 0) 'start recursive
Console.ReadLine() 'pause the console
End Sub
Sub Recursion(ByVal depth As Integer, ByVal start As Integer, ByVal count As Integer)
'depth -> the recursion's depth (the 'for' count)
'start -> where the next for starts
'count -> current number count
If count = TargetNumber Then
'when [count] equals [TargetNumber] print the combination nums
For j As Integer = 0 To nums.Count - 1
Console.Write(nums(j) & " ")
Next
Console.Write(vbCrLf)
Return
ElseIf depth = BasicNums.Length - 1 Then
'stop the recursion when the recursion meets the length of [BasicNums]
Return
End If
For i As Integer = start To BasicNums.Length - 1
nums.Add(BasicNums(i))
Recursion(depth + 1, i + 1, count + BasicNums(i))
nums.Remove(BasicNums(i))
Next
End Sub
End Module
Example Input:
7
Output:
1 2 4
1 6
2 5
3 4
7

Loop variable ends with a value one above expected

In VBA, running in Excel, I am running a basic loop that fills an array with values. The code is as below.
What I find curious, is the value of Counter starts at 0, yet ends at 7, rather than 6. I can note this when I'm looking in the Locals window and running the code step-by-step. It seems the value becomes 7 on its last instance of running 'Next'
Is this normal, or is there something I'm doing wrong?
It doesn't seem to change the outcome here, but if I'm using more complicated code, I want to be sure this is what I should be expecting.
Sub ArrayLoop()
Dim myArray(6) As String
Dim Counter As Integer
For Counter = 0 To 6
myArray(Counter) = Range("A1").Offset(Counter, 0).Value
Next
End Sub
This is normal: last iteration of the loop increments Counter to 7 and triggers the exit from loop
Counter = 7 ( > 6 )
There are algorithms based on the exit value of the Counter:
Option Explicit
Sub ArrayLoop()
Dim myArray(6) As String
Dim Counter As Integer
For Counter = 0 To 6
myArray(Counter) = Range("A1").Offset(Counter, 0).Value
Next
Do
Debug.Print Counter '---> 7, 6, 5, 4, 3, 2, 1
Counter = Counter - 1
Loop While Counter > 0
Debug.Print Counter '---> 0
End Sub
remember that arrays are zero indexed. So technically the 7th time through the loop it should give you some sort of out of bounds error. Although there is technically nothing wrong with the way you are adding your values to the array.
Also remember that counter increments +1 each time after the loop is completed.
if you wanted it to only use 6 values you would have to change to
For Counter = 0 To 5
myArray(Counter) = Range("A1").Offset(Counter, 0).Value
Next
this would start at 0 the first time through the loop add the value to the array with a 0 index, then increase the index each time +1 and increase the offset by 1 row each time through the loop. And it would only run the loop 6 times.

Intersection of the Arraylists in VB

I've a legacy code base where I've four ArraysLists (different sizes). I want to compare these four arraylists and save the same values in a separate Array/Arraylist.
The arrays can have same values multiple times since ordering is not important. You can say that I just need the intersection of the ArrayLists.
The following code works, but of-course this is not the best way to do, looping on all the arrays-
For i = 0 To arr.Count - 1 Step 1
For j = 0 To arr1.Count - 1 Step 1
If arr.Item(i) = arr1.Item(j) Then
For k = 0 To arr2.Count - 1 Step 1
If arr.Item(i) = arr2.Item(k) Then
For l = 0 To arr3.Count - 1 Step 1
If arr.Item(i) = arr3.Item(l) Then
// the value arr.Item(i) exists in all 4 arrys
// save this to another array
End If
Next
End If
Next
End If
Next
Next
Since my arrayList size could be in thousands, that's not the way I want to know how should I sort out this.
Thanks.
PS. Sorry if this is a duplicate question, since I was not able search this anywhere (I'm new to VB).
you could use ArrayList.Contains to shorten / simplify things:
For i As Integer = 0 To arr.Count - 1
If Arr1.Contains(arr(i)) AndAlso Arr2.Contains(arr(i)) _
AndAlso Arr3.Contains(arr(i)) AndAlso Arr4.Contains(arr(i)) Then
// the value arr(i) exists in all 4 arrayLISTS
// save this to another array
End If
Next
Probably wont be a lot different in speed, but the code is sure easier to read. NB: AndAlso is important in this because it short circuits the later tests when it the result is false.

Resources