fill one dimensional dynamic array - excel

I have code like this.
Dim sums() As Single
dim n as integer
For n = 0 To ActiveCell.Value - 2
sums(n) = Abs(Application.WorksheetFunction.SumIf(Range(Cells(i + m, 6), Cells(j - 1, 6)), Range("F" & i + m).Value, Range(Cells(i + m, 17), Cells(j - 1, 17))))
Next n
I am getting an error message for sums(n)= .... I would like to fill array with values according to formula. E.G I have in activecell value 3, then I would like to have array with 2 values like sums(0) = abs(sumif..) and sums(1)= abs(sumif..).
I tried to calculate the formula without an array as sum1 = formula and it worked, but as soon as I changed it to the array because sometimes I will have there 2, 3 an more values in it, it doesn't work.

try the below changes:
Option Explicit
Sub sums_()
Dim sums() As Single
Dim n As Integer
Dim i As Integer
Dim m As Integer
Dim j As Integer
'assign the values or range of values for i,m,j
ReDim sums((ActiveCell.Value - 2) + 1)
For n = 0 To ActiveCell.Value - 2
sums(n) = Abs(Application.WorksheetFunction.SumIf(Range(Cells(i + m, 6), Cells(j - 1, 6)), Range("F" & i + m).Value, Range(Cells(i + m, 17), Cells(j - 1, 17))))
Next n
End Sub

You need to size your array first. Use Redim to do so before your loop:
Redim sums(0 to ActiveCell.Value - 2)
For n = 0 To ActiveCell.Value - 2
...
You can use Redim multiple times in your code, but note that if you want to keep the content of the array, you have to use Redim preserve and that is rather slow because the complete array is rebuild. So you should avoid to use Redim preserve within a loop.

Related

Can't write array to sheet

Dim HighScoreOneHourData() As Integer
Dim HighScoreOneHourDates() As String
ReDim HighScoreOneHourData(1 To UBound(SA, 1) - 3)
ReDim HighScoreOneHourDates(1 To UBound(SA, 1) - 3)
For j = 4 To UBound(SA, 1)
HighScoreOneHourData(j - 3) = CInt(Val(SA(j, PositionInArray + DataColumn + 2)))
HighScoreOneHourDates(j - 3) = SA(j, 1)
Next j
SortSheet.Range("A1:A" & UBound(HighScoreOneHourDates)) = HighScoreOneHourDates
SortSheet.Range("B1:B" & UBound(HighScoreOneHourData)) = HighScoreOneHourData
When these last two lines in the example above are executed all the cells in the sheets are filled with the first element from the arrays.
HighScoreOneHourDates is an array filled with consecutive dates. Still only the first date is printed to the sheet.
I've stopped the code and checked the state of the arrays and the they are correctly filled.
Anyone knows why the cells are filled with the first element?
It's been explained why 1D arrays don't work for you. A better fix is to Dim them as 2D
ReDim HighScoreOneHourData(1 To UBound(SA, 1), 1 To 1) As Integer
ReDim HighScoreOneHourDates(1 To UBound(SA, 1), 1 To 1) As String
For j = 4 To UBound(SA, 1)
HighScoreOneHourData(j - 3, 1) = CInt(Val(SA(j, PositionInArray + DataColumn + 2)))
HighScoreOneHourDates(j - 3, i) = SA(j, 1)
Next j
SortSheet.Range("A1:A" & UBound(HighScoreOneHourDates, 1)) = HighScoreOneHourDates
SortSheet.Range("B1:B" & UBound(HighScoreOneHourData, 1)) = HighScoreOneHourData
A 1D array always wants to be placed on a sheet in a row, not a column. That's why you only get the first element repeated. You need to re-orient the array to put it in a column, or make your arrays 2D (1 To numHere, 1 To 1)
Note there is a limit to the array size you can pass to Transpose of around 63-64k elements.
Assuming your arrays are 1-based you can do this:
SortSheet.Range("A1:A" & UBound(HighScoreOneHourDates)) = _
Application.Transpose(HighScoreOneHourDates)
for example.

How to use Excel VLOOKUP for same letters but different word

I need to find the values of words with the same letters but different order of letters. I tried using vlookup but it didn't work, any suggestions how to do that? For example, the letters are the same in the photo, but their order is different and I cannot find the value.
Another alternative LAMBDA() related option using REDUCE():
Formula in E1:
=XLOOKUP("",REDUCE(A$1:A$3,MID(D1,SEQUENCE(LEN(D1)),1),LAMBDA(a,b,SUBSTITUTE(a,b,"",1))),B$1:B$3)
Or; spill the entire range at once wrapping the above in BYROW():
Formula in E1:
=BYROW(D1:D3,LAMBDA(a,XLOOKUP("",REDUCE(A$1:A$3,MID(a,SEQUENCE(LEN(a)),1),LAMBDA(b,c,SUBSTITUTE(b,c,"",1))),B$1:B$3)))
The above would assume lookup values that are of the exact same length. To avoid false positives we should probably concatenate our starting value first:
=XLOOKUP(D1,REDUCE(A$1:A$3&D1,MID(D1,SEQUENCE(LEN(D1)),1),LAMBDA(a,b,SUBSTITUTE(a,b,"",1))),B$1:B$3)
And respectively:
=BYROW(D1:D3,LAMBDA(a,XLOOKUP(a,REDUCE(A$1:A$3&a,MID(a,SEQUENCE(LEN(a)),1),LAMBDA(b,c,SUBSTITUTE(b,c,"",1))),B$1:B$3)))
With Office 365 we can use XLOOKUP with some other dynamic array formula:
=XLOOKUP(CONCAT(SORT(MID(D1,SEQUENCE(,5),1),1,1,TRUE)),BYROW(MID($A$1:$A$3,SEQUENCE(,5),1),LAMBDA(A,CONCAT(SORT(A,1,1,TRUE)))),$B$1:$B$3,"")
This will order the letters in alphabetical order virtually so that they will find the matches.
If one does not have Office 365 this will be easier with vba. Based on an older answer: Excel formula to take string value from cell and sort its characters in alphabetical order
We can use the following UDF's to return the needed sorted values:
Function sortletterarr(rng As Range)
If rng.Columns.Count > 1 Then Exit Function
If rng.Rows.Count <= 1 Then Exit Function
Dim out()
out() = rng.Value
Dim srtArr() As String
Dim i As Long, j As Long, k As Long
Dim a As Long
For a = LBound(out, 1) To UBound(out, 1)
ReDim srtArr(1 To Len(out(a, 1)))
srtArr(1) = Mid(out(a, 1), 1, 1)
For i = 2 To UBound(srtArr)
For j = 1 To UBound(srtArr)
If srtArr(j) = "" Then
srtArr(j) = Mid(out(a, 1), i, 1)
Exit For
ElseIf IIf(Asc(Mid(out(a, 1), i, 1)) > 96, Asc(Mid(out(a, 1), i, 1)) - 32, Asc(Mid(out(a, 1), i, 1))) <= IIf(Asc(srtArr(j)) > 96, Asc(srtArr(j)) - 32, Asc(srtArr(j))) Then
For k = UBound(srtArr) To j + 1 Step -1
srtArr(k) = srtArr(k - 1)
Next k
srtArr(j) = Mid(out(a, 1), i, 1)
Exit For
End If
Next j
Next i
out(a, 1) = Join(srtArr, "")
Next a
sortletterarr = out
End Function
And
Function sortletter(rng As Range)
If rng.Count > 1 Then Exit Function
Dim srtArr() As String
Dim i&, j&, k&
ReDim srtArr(1 To Len(rng))
srtArr(1) = Mid(rng, 1, 1)
For i = 2 To UBound(srtArr)
For j = 1 To UBound(srtArr)
If srtArr(j) = "" Then
srtArr(j) = Mid(rng, i, 1)
Exit For
ElseIf IIf(Asc(Mid(rng, i, 1)) > 96, Asc(Mid(rng, i, 1)) - 32, Asc(Mid(rng, i, 1))) <= IIf(Asc(srtArr(j)) > 96, Asc(srtArr(j)) - 32, Asc(srtArr(j))) Then
For k = UBound(srtArr) To j + 1 Step -1
srtArr(k) = srtArr(k - 1)
Next k
srtArr(j) = Mid(rng, i, 1)
Exit For
End If
Next j
Next i
sortletter = Join(srtArr, "")
End Function
Put both in a normal module attached to the worksheet.
then we can use INDEX/MATCH:
=INDEX($B$1:$B$3,MATCH(sortletter(D1),sortletterarr($A$1:$A$3),0))
And it will return what we want.
This is definitely a primitive approach, but it does work if, as your post indicates, all of your references are of a uniform length, and will work (as an array formula) in versions of Excel from 2007 upwards:
=INDEX($B$1:$B$3,MATCH(SUM(CODE(MID(D1,ROW($1:$5),1))),MMULT(CODE(MID($A$1:$A$3,TRANSPOSE(ROW($1:$5)),1)),ROW($1:$5)/ROW($1:$5)),0))
If your references are not all of the same length (5 in your example) then this formula will not work (even as updated in later versions of Excel, it could compute the same numeric value for 2 entirely different character sequences of unequal length).
(if you opt for the VBA solution in the first answer then this article will show you where to put it)
Edit 2-May-2022
JvdV's feedback has indicated a potential issue with the foregoing so, below is an alternate approach, albeit using a helper column (C):
the formula in column C1 is
=SUMPRODUCT(LARGE(CODE(MID(A1,ROW($1:$5),1)),ROW($1:$5)),ROW($1:$5)*128)
(which should copied down for each cell of your data)
and the formula in F1 is
=INDEX($B$1:$B$5,MATCH(SUMPRODUCT(LARGE(CODE(MID(E1,ROW($1:$5),1)),ROW($1:$5)),ROW($1:$5)*128),$C$1:$C$5,0))

Finding the length of a VBA array [duplicate]

Is This code correct for determining the number of elements in a single dimension variant array in Excel VBA. Supposing I have a variant array named Array1 with k elements.
Dim n as Integer
n = UBound(Array1)
To get an accurate count, you need to do UBound - LBound + 1. This is because arrays don't have to go from index 1 to n, they can start at basically any index you want. Here's an example where it goes from 3 to 7, which is a total of 5 elements (3, 4, 5, 6, and 7):
Sub tgr()
Dim Array1(3 To 7) As Variant
Dim lNumElements As Long
lNumElements = UBound(Array1) - LBound(Array1) + 1
MsgBox lNumElements
End Sub
Typically, you need the number of elements when looping through them using a For loop. In this case, the most straight forward way is to write
For i = LBound(A) To UBound(A)
Debug.Print "A(" & i & ") = " & A(i)
Next i

Error pops when I call a function to use the data I took from a sheet in other macros. Can anyone explain why it says 'object required'?

I want to store data from an excel sheet into arrays and then use them in different macros. I've written the following function to store data then I call it in different macros but an error pops up and says "Object required". Please help me.
Public Function data()
Dim i, j, t1, t2 As Integer
Dim x As Range
Dim dt() As Date
Dim price(), bch() As Single
Dim chp(), chb() As Integer
Sheets("Data").Select
Range("B8").Select
Set x = ActiveSheet.UsedRange.Range("B8").End(xlDown).Rows.Count 'getting the range
For i = 1 To x 'stores data into the array
Cells(i + 8, 1).Value = dt(i - 1)
Cells(i + 8, 2).Value = price(i - 1)
Cells(i + 8, 3).Value = bch(i - 1)
Cells(i + 8, 4).Value = chp(i - 1)
Cells(i + 8, 5).Value = chb(i - 1)
Next
End Function
You can't set a Range to be a number. So the statement
Set x = ActiveSheet.UsedRange.Range("B8").End(xlDown).Rows.Count
won't work.
ActiveSheet.UsedRange.Range("B8").End(xlDown) will be referring to a single cell, so its Rows.Count will always return the number 1.
So you are getting an error because you are trying to set x (a Range) to 1 (a Long).
Judging by your use of x in the For i = 1 to x loop, and your use in that loop of i + 8, you seem to be trying to find how many rows are being used below row 8 (so, if the last used row was row 10, you seem to want x to be 2 so that the loop updates rows 9 and 10), so you really want to use:
Dim x As Long
x = ActiveSheet.Range("B8").End(xlDown).Row - 8
FYI, also be aware that
Dim i, j, t1, t2 As Integer
is equivalent to
Dim i As Variant, j As Variant, t1 As Variant, t2 As Integer
not to
Dim i As Integer, j As Integer, t1 As Integer, t2 As Integer

Populating multi dimensional arrays with 0

I'm trying to populate part of an array with 0's and wondering if there was a better way then to loop through it.
I know I could use Dim tempArr as double to do this but the first column in the array contains strings.
I'm currently using
Dim tempArr as Variant
ReDim tempArr(1 To 6, 1 To 1 + (EndWeek - (BeginWeek - 1)))
tempArr(1, 1) = "Monday - Friday"
tempArr(2, 1) = "Saturday"
tempArr(3, 1) = "Sunday"
tempArr(4, 1) = "Bank Holiday"
tempArr(5, 1) = "Annual Leave"
tempArr(6, 1) = "Apprentice"
For i = 1 To 6
For j = 2 To UBound(tempArr, 2)
tempArr(i, j) = CDbl(0)
Next j
Next i
But surely there's a better way?

Resources