I want to rotate values from a separate Excel file like this:
To a vertical list:
I mean, after every ninth value, I want the program to start a new column (as in the picture).
I manage to do this manually (ofc B) ) when the different "sheets" are on the same document (Sheet1, Sheet2 etc).
Is this even possible what I am trying, without too much further programming? Should I be using Excel macros? I appreciate all the help I get..!
Store the data matrix in an array and slice off transposed 'rows' of values.
Dim x As Long, vVALs As Variant
With Worksheets("Sheet1")
vVALs = .Range("A2:I5").Value2
For x = LBound(vVALs, 1) To UBound(vVALs, 1)
.Cells(7, 1).Offset((x - 1) * UBound(vVALs, 2)).Resize(UBound(vVALs, 2), 1) = _
Application.Transpose(Application.Index(vVALs, x, 0))
Next x
End With
Related
I am writing a VBA script to check all measuring point, who are part of the selection have inspection orders. For this I need to extract a large amount of measering point (ca. 2721) and use them as an input in another transaction.
The problem I have is: What is the most efficient way to extract / export a large amount of data from SAP in a way that I can paste them as an input in SAP?
I can make an export, but I cannot access the exported Excel-file through VBA. I can loop through the datarows and copy every single cell, but this is very slow, as shown below.
row = 1
For i = 1 To session.FindById("wnd[0]/usr/cntlGRID1/shellcont/shell").RowCount - 2
session.FindById("wnd[0]/usr/cntlGRID1/shellcont/shell").CurrentCellRow = i
ThisWorkbook.Sheets("Output2").Cells(row, 1) = session.FindById("wnd[0]/usr/cntlGRID1/shellcont/shell").GetCellValue(i - 1, "TPLNR")
ThisWorkbook.Sheets("Output2").Cells(row, 2) = session.FindById("wnd[0]/usr/cntlGRID1/shellcont/shell").GetCellValue(i - 1, "POINT")
row = row + 1
Next
You should
use an array - instead of writing directly to the sheet
use with to not call session.FindByID... multiple times
Dim arrData As Variant, i As Long
With session.FindById("wnd[0]/usr/cntlGRID1/shellcont/shell")
ReDim arrData(1 To .RowCount - 2, 1 To 2)
For i = 1 To .RowCount - 2
.CurrentCellRow = i
arrData(i, 1) = .GetCellValue(i - 1, "TPLNR")
arrData(i, 2) = .GetCellValue(i - 1, "POINT")
Next
End With
With ThisWorkbook.Sheets("Output2")
.Resize(UBound(arrData, 1), 2).Value = arrData
End With
But maybe it's worth to look into Powerquery to achieve what you want.
I saw quite a number of questions/answers along these lines, but after reading a bunch of them, I'm still confused. I'm sorry if this is the nᵗʰ time a variant of this has been asked.
I can't figure out why this code dies on line 5 with a "subscript out of range" error in VBA (Excel for Mac v16.38):
Public Function array_test()
Dim arr As Variant
Dim array_slice As Variant
arr = Range("TestData!B27:F32").Value2
array_slice = arr(2) 'dies here with error 9
array_test = array_slice
End Function
Looking at the values pane, arr is clearly a Variant/Variant(1 to 6, 1 to 5) with all the expected data. There is nothing special about the cells, just non-formula data.
Even if I change the declarations to arr() and array_slice() or remove ".Value2", I get the same results. Even trying Application.WorksheetFunction.Index(arr, 2) rather than arr(2) gets me nowhere.
What am I missing?
P.S. I'm a C/Python programmer normally, so I'm thinking of arrays in those terms.
Usually one would loop an 2D-array for it's elements, however, since you specifically mentioned you would like to slice it through VBA, you could use Application.Index. For example try:
array_slice = Application.Index(arr, 2, 0) 'Slice 2nd row into 1D-array.
The idea here is to feed Application.Index with a static '2' which represents the row of interest. In the same fashion you could slice a specific column of interest, though if you need this to be an 1D-array, you'd need to use Application.Transpose, however there are limitations to this method:
With Application
array_slice = .Transpose(.Index(arr, 0, 2)) 'Slice 2nd column into 1D-array.
End With
When you copy data from a Range and the Range contains more than one cell, you get n 2-dimensional array in any case (even if you have only one row or one column).
To access a single value from that array, you have to provide both indices, like arr(2, 1). However, if you want to get a one-dimensional array, containing all values from a row (first index) or a column (second index), you need to create that array by your own - there is no slice function in VBA. You can dimension an array at runtime using the ReDim-command:
Dim array_slice(), i As Long
ReDim array_slice(LBound(arr, 1) To UBound(arr, 1))
For i = LBound(arr, 1) To UBound(arr, 1)
array_slice(i) = arr(i, 2)
Next i
To get the values of a column, use
Dim array_slice(), i As Long
ReDim array_slice(LBound(arr, 2) To UBound(arr, 2))
For i = LBound(arr, 2) To UBound(arr, 2)
array_slice(i) = arr(2, i)
Next i
I often make a lot of scatter plots (column j vs column i) in a single Worksheet. I want to export them as png/jpg files. Each plot would need a sensible file name. I have thought that the file name could be something like plot_[column i]_[column j].png.
How do I get the column (like C or AE) from each plot (or ActiveChart)? Then I can create a file name string to be fed in to the Export method. I am a complete beginner for VBA macros, but understand some Visual Basic.
You can extract that information from the source data string using text functions. The source data is available using .SeriesCollection:
activesheet.chartobjects("Chart 1").chart.SeriesCollection(1).Formula
will return something like this:
"=SERIES(,Sheet1!$A$1:$A$4,Sheet1!$B$1:$B$4,1)"
That contains the two columns you need, "A" and "B". You can extract them using text functions like INSTR(), MID(), and LEFT(). Here is an example using debug.print to output the columns. I'm assuming you already know how to export them since that was not included in your question.
Sub FindSourceColumns()
Dim sourcedata, firstcolumn, secondcolumn As String, c as chartobject
for each c in activesheet.chartobjects
sourcedata = c.Chart.SeriesCollection(1).Formula
firstcolumn = Mid(sourcedata, InStr(sourcedata, "!$") + 2, 5)
firstcolumn = Left(firstcolumn, InStr(firstcolumn, "$") - 1)
Debug.Print firstcolumn
secondcolumn = Mid(sourcedata, InStr(InStr(sourcedata, "!$") + 2, sourcedata, "!$") + 2, 5)
secondcolumn = Left(secondcolumn, InStr(secondcolumn, "$") - 1)
Debug.Print secondcolumn
next c
End Sub
I want to filter worksheet excluding all values stored in another worksheet in column A. For that store all the values into an array
xArray = Worksheets("MainRef").Range("A1:A" & Worksheets("MainRef").Cells(Rows.Count, 1).End(xlUp).Row).Value2
And trying to filter with following command
rngTar.AutoFilter Field:=2, Criteria1:=xArray, Operator:=xlFilterValues
but its not work. Kindly guide me how to do this.
The problem here is your array xArray.
xArray = Worksheets("MainRef").Range("A1:A" & Worksheets("MainRef").Cells(Rows.Count, 1).End(xlUp).Row).Value2
When you store values in array using above line it creates a 2-dimensional array. The first dimension is the rows and second dimension is the columns. When you'll see the Type of your array in Local window it displays Variant(1 to 5, 1 to 1) where 5 is number of rows(mentioned 5 just for example) and 1 is number of columns.
So when you use xArray to filter the range it will not work as a 2 dimensional array is created even you have selected only one column.
Instead you can use following approach to load values in array:
Dim N As Long
With Sheets("MainRef")
N = .Cells(Rows.Count, "A").End(xlUp).Row
ReDim xArray(1 To N)
For i = 1 To N
xArray(i) = .Cells(i, 1)
Next i
End With
I have a spreadsheet, BO2009, that is 300k rows long. Only one column contains a formula The others are all pasted values so only one formula needs to be calculated in the entire workbook. Here is the formula: =IFERROR(INDEX('RE2009'!H:H,MATCH('BO2009'!A2,'RE2009'!A:A,0)),1) This formula is copied down to the bottom of the sheet, so 300k times.
RE2009 sheet has 180k rows. 'RE2009'!H:H contains decimal numbers and 'RE2009'!A:A, 'BO2009'!A:A contain ID codes--an 8 character combination of numbers and letters. Both 'RE2009'!A:A, 'BO2009'!A:A are formatted as general.
I use INDEX/MATCH all the time and while most of my spreadsheets are not 300k long, 60k-100k is typical. Right now it takes a couple minutes of my CPU devoting 99% to Excel in order to finish the calculation.
Is that normal? Is there any way to improve Excel's performance?
On top of that I am getting inaccurate results: instead of 0.3 the lookup produces an error.
As suggested, I have filtered the BO2009 sheet down to 80k rows, but still have the same issues. I decided to look at a single formula in particular: =IFERROR(INDEX('RE2009'!H:H,MATCH('BO2009'!A108661,'RE2009'!A:A,0)),1) to see if it worked correctly. The ID that it is looking for with the MATCH function is the 3rd entry in the lookup array, but it still isn't able to produce the correct value (0.3)
It seems that you've found a satisfactory solution to your problem(s) but as a matter of curiosity, you may wish to time this against your current formula based solution to see if there is a measurable increase in speed.
Sub index_match_mem()
Dim v As Long, vVALs As Variant, vTMP As Variant
Dim dRE2009 As Object
Debug.Print Timer
Application.ScreenUpdating = False
With Worksheets("RE2009")
With .Cells(1, 1).CurrentRegion
With .Resize(.Rows.Count, 8)
vTMP = .Cells.Value2
End With
End With
End With
Set dRE2009 = CreateObject("Scripting.Dictionary")
dRE2009.CompareMode = vbTextCompare
For v = LBound(vTMP, 1) To UBound(vTMP, 1)
If Not dRE2009.exists(vTMP(v, 1)) Then _
dRE2009.Add Key:=vTMP(v, 1), Item:=vTMP(v, 8)
Next v
With Worksheets("BO2009")
With .Cells(1, 1).CurrentRegion
With .Resize(.Rows.Count - 1, 2).Offset(1, 0)
vVALs = .Cells.Value2
For v = UBound(vVALs, 1) To LBound(vVALs, 1) Step -1
If dRE2009.exists(vVALs(v, 1)) Then
vVALs(v, 2) = dRE2009.Item(vVALs(v, 1))
Else
vVALs(v, 2) = 1
End If
Next v
.Cells = vVALs
End With
End With
End With
dRE2009.RemoveAll: Set dRE2009 = Nothing
Application.ScreenUpdating = True
Debug.Print Timer
End Sub
This will produce static values in column B of the BO2009 worksheet. The elapsed start and stop in seconds will be in the VBE's Immediate window (Ctrl+G)