VBA code to paste a range into Excel as an array? - arrays

So I have a range of items plugged in an Excel spreadsheet and I am looking for some code to paste those same values as an array (i.e. a ctrl + shift + enter formula) elsewhere in my spreadsheet. I've been trying to use the Range.FormulaArray property but can't seem to get it to work.
As an example, I have a list of text items such as:
Apple
Orange
Banana
And I want to paste these items as a hardcoded array elsewhere in the spreadsheet so that the formula in cell A1 will read:
={"Apple";"Orange";"Banana"}
And the values will spill in to the subsequent two cells
I'm using the latest version of Office 365.
Any ideas?

Use .Formula2:
Sub EasyAsOneTwoThree()
Range("A1").Formula2 = "={""Apple"";""Orange"";""Banana""}"
End Sub
As you see, it spills down very nicely.
(notice I had to double-up on the double quotes)

Related

How to get array with values into one column

In excel I have two columns (A and B) filled with text values and I want to get all the values from the two column into one column (C) and it needs to be dynamic
example:
Column A: {car, plane, boat}
Column B: {bike, motor}
Column C: {car, plane, boat, bike, motor}
I hope someone can help me!
use:
=QUERY(FLATTEN(A:C); "where Col1 is not null")
This will work in both Excel(any version) and Google Sheets: Put this in C1 and copy down till you have enough cells filled to capture both lists maximum lengths:
=INDEX(A:B,IF(ROW($ZZ1)>COUNTA(A:A),ROW($ZZ1)-COUNTA(A:A),ROW($ZZ1)),IF(ROW($ZZ1)>COUNTA(A:A),2,1))&""
With Office 365 Excel:
=LET(
rng1st,A:A,
rng2nd,B:B,
cnt1st,COUNTA(rng1st),
cnt2nd,COUNTA(rng2nd),
sq,SEQUENCE(cnt1st+cnt2nd),
INDEX(CHOOSE({1,2},rng1st,rng2nd),IF(sq>cnt1st,sq-cnt1st,sq),IF(sq>cnt1st,2,1)))
Put that in C1 and the results will spill automatically:
Google Sheets has a FLATTEN function which allows you to do this, but there is no equivalent function in Excel.
There is a workaround though, which does combines the 2 columns in the order of their rows:
This works in Excel Version 2019 or later
=FILTERXML("<a><b>"&TEXTJOIN("</b><b>",TRUE,A:B)&"</b></a>","//b")
=IF(SEQUENCE(ROWS(range1)+ROWS(range2))<ROWS(range1)+1,range1,INDEX(range2,MOD(SEQUENCE(ROWS(range1)+ROWS(range2),,ROWS(range2)-ROWS(range1)),ROWS(range2))+1,SEQUENCE(1,COLUMNS(range2))))
This will stack range2 under range1 in Excel (365) this also works for ranges with 2 columns, or more
If the amount of the rows won't be changed
=IFERROR(INDEX($A$1:$A$3, ROWS(C1:$C$1)), IFERROR(INDEX($B$1:$B$2, ROWS(C1:$C$1)-ROWS($A$1:$A$3)), ""))
ctrl + shift + enter
If the amount of the rows can be changed
=IFERROR(INDEX(INDIRECT("$A$1:$A$"&COUNTIF(A:A,"")), ROWS(C1:$C$1)), IFERROR(INDEX(INDIRECT("$B$1:$B$"&COUNTIF(B:B,"")), ROWS(C1:$C$1)-ROWS(INDIRECT("$A$1:$A$"&COUNTIF(A:A,"*")))), ""))
ctrl + shift + enter

Link two cells in google sheets with autofill

First of all I would like to thank you for your time.
I have a google data studio report that extracts data from a google sheet. The data studio sheet gets values from a google form (in the form of another tab in the sheet). Altough the cells are linked, right now I have to drag the cells in the data studio sheet to pull the values from the forms sheet. If there are no values it can´t pull anything and I would like to have real time values in the google data studio as soon as a form is filled.
Right now all I have is a simple (='Form '!C55) to pull. What I would like to do is if there is a new value in the following cell in the forms sheets then the following cell in the data studio sheets pulls it so it can go to the report in dat studio.
Cheers to all!
Try this formula, in column A, after your last row of good data. So perhaps in Dados!A91. Note you will need to first delete everything in all of the cells below and to the right of A91, since this formula is filling everything:
=QUERY('Formulário '!A9:O;"select A,G,D,J,M,H,E,K,N,I,F,L,O where B <> '' ";0)
This queries your Formulário sheet, and pulls all of the data starting in row 9 (since that is what you were showing with your formula before), and selects all of the correct columns in order.
Please test it out with a test form submission, to see that it works as expected, and that it is copying the correct columns, in the right order. Let me know of any questions or issues.
I'm not positive how sheet updates work when there is no active user logged into the sheet, but I suppose when Data Studio goes to pull from Dados, it will first ensure that it has the latest data from all formulas.
Update
To have the Max and Min values,which you say should be the same all the way down the column, add a formula like the following in the header row (row 1) of your Formulario sheet:
={"Cloro Max.";ArrayFormula(IF(LEN(A2:A);1,5;""))}
That gives a value of 1,5 for a column labelled Cloro Max. Be sure to delete anything from row 2 down, in that same column, or the array formula gives a #REF error, since it can't put data when there is already data entered in those lower cells.
You can change the text to create a Max or Min column for each value you want, in columns Q to V. Change the 1,5 to whatever number you want, such as 0,5 for Cloro Min.
It will always add the value(s) to each new row as it gets added from a submitted form response.

Array result from INDIRECT

So, I have a Google Sheet connected to a Google Form that I use for debugging a series of games. Each game has a Unit number and an Activity number.
I added to the sheet a column that, basing on the Unit and on the Activity, retrieves the name of the developer, contained in another sheet.
=INDIRECT("Developers!"&CHAR(C1+64+1)&(B1+1))
(I have to add 1 to each value because the other table has headers)
The formula does work on a single cell, but it's not applied to the new lines inserted by the Google Form.
I've seen that ARRAYFORMULA() returns an array that automatically populates the cells below.
Is there a command I can use to apply a formula to an array of values and have an array of results returned?
if you want to get just a range do:
=INDIRECT("Developers!"&ADDRESS(B1+1, C1+1, 4)&":"&ADDRESS(ROWS(A:A), C1+1, 4))
or populated range:
=INDIRECT("Developers!"&ADDRESS(B1+1, C1+1, 4)&":"&ADDRESS(COUNTA(B:B), C1+1, 4))

Excel - setting a dynamic print area for a range of cells covered by an array formula

I have a spreadsheet with a page (Sheet 3) which I would like to export as a PDF (using a macro to export the pdf).
Currently, this links in to another worksheet, in which a user can put in a date range to pull out relevant data from a larger worksheet. This uses the following array formula to populate the data on Sheet 3:
=IFERROR(INDEX(Sheet1!$V$3:$W$5998,SMALL(IF((Sheet1!$C$3:$C$5998>=Crynodeb!$D$3)*(Sheet1!$C$3:$C$5998<=Crynodeb!$F$3)*(Sheet1!$V$3:$V$5998<>""),ROW(Sheet1!$V$3:$W$5998)-2),ROW(18:18)),1),"")
The array formula on Sheet 3 has been applied to around 6000 rows of data. So there is potential for 6000 lines of data to be returned. However, depending on the criteria the user has put in, maybe only 5 rows of data will be returned.
In addition to this, I've applied cell formatting to the 6000 rows so that there's a print-friendly line in between the rows of data.
However, because this has been applied to the 6000 rows of data, there could be 61 or so pages exported, when in reality only a page worth of data is displaying.
Is there an easy way to continue having the array formula applied across a large range, while limiting the print function to only apply to pages containing data that is returned from the array formula?
I'm also using the Format > AutoFit Row Height function to adjust the row height in accordance to the length of the returned items, but at the moment I think I have to do this manually every time I return data. Is there a way of applying that automatically to adjust around the content of the page?
Many thanks
Since you want to export the data to PDF via macro, we can just put everything you want into that one macro.
The macro needs to find the range that has values. From your example, I'm assuming there will always be data returned starting in A3; and then there will no blanks in Column A until the end of the data.
So, this macro starts at A3 and looks at each cell until it finds a blank value to determine where the data ends.
I'm also assuming you have a fixed number of columns of data. I can only see 2 columns so I've used that figure in macro. You can update the code where indicated to the actual number of columns.
Then, from A1 to the last row and column of the data, it autofits the rows and then saves that range as a PDF.
Public Sub SaveCopy()
Dim intLastRow As Integer
'Loops through column A to find last row with data
intLastRow = 3
Do While Cells(intLastRow + 1, 1).Value <> ""
intLastRow = intLastRow + 1
Loop
'With the range of data...
'NOTE: REPLACE '2' WITH ACTUAL NUMBER OF COLUMNS OF DATA
With Range("A1", Cells(intLastRow, 2))
'Ensure text is wrapping - required to autofit
.WrapText = True
'Autofit row height
.Rows.AutoFit
'Save as PDF
.ExportAsFixedFormat Type:=xlTypePDF, _
Filename:=ThisWorkbook.FullName, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=True
End With
End Sub
This is a basic export and will just save the PDF into the same location as the file and with the same filename (including the excel file extension) and just appends .PDF file extension.
There are various options for handling the filename and location of the PDF. With more information of what is required I could help provide a robust solution.
Alternatively, you can remove the line of code for exporting to PDF and replace it with just ".Select"
This will select the range of data and then you can manually save to PDF. Just use Save As... change the type to PDF, click Options and choose "Selection" in the "Publish what" section.
If any of my assumptions are incorrect, please let me know.

Loop and compare values from array

In Sheet1 I have a single column with populated cells from 1-20 row with regular numbers. Look at picture bellow:
In Sheet2 I have also a single column, cells are starting from 5-25. If I enter some values into these cells, in Sheet1 from cell with that same value to column "D" background color is changed. Look at pictures bellow to see how it works:
I'm doing it with this piece of code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 1 And Target.Row >= 5 Then
If Target.Offset(0, 0).Text <> "" Then
Dim n As Long
For n = 5 To 25
If Target.Offset(0, 0).Value = Worksheets("Sheet1").Range("A" & n).Value Then
Worksheets("Sheet1").Range("A" & n & ":D" & n).Interior.ColorIndex = 3
End If
Next n
End If
End If
End Sub
Now, I'd like to make some kind of check every time Sheet1 is activated, in a way if there are no values in cells Interior.ColorIndex = xlNone for all the cells in Range("A1:A20"), if there is a value in some cells Interior.ColorIndex = 3 for those cells. I was thinking about to put these values into an array and then loop through it to compare values but I'm new to VBA so help would be welcome. If there is a better solution, just bring it on.
Also, I'd like to make a piece of code for a situation if I replace value 12 with 17 that Interior.ColorIndex of cell that contains 12 goes to xlNone and of 17 Interior.ColorIndex goes to "3".
So, every suggestion is welcome.
No VBA is needed, as pnuts says.
The easiest way to do this with the colours is with Conditonal Formatting using Formula to check the value of the cells in column A on one sheet against the values in the rows where you want the colour to change and apply the formatting.
See:
MSDN Office Online: Use a formula to apply conditional formatting
Contextures.com: Excel Conditional Formatting -- Examples
Chip Pearson Excel MVP: Conditional Formatting
J-Walk Mr Spreadsheet: Conditional Formatting
BUT if you want VBA, then you can do this in the workbook and worksheet event handlers.
Worksheet Selection/Activation:
in Excel on Sheet1, right-click on the sheetname at the bottom, and click View Code. This will open the class module for Sheet1 in the VB Editor.
At the top of the code module on the left, select Worksheet from the drop-down, and on the right drop-down, click the Activate event-handler.
This will create an empty sub-routine that will be executed by Excel everytime that you select the Sheet1 worksheet.
In that code you can make your checks.
Cell changes on sheet2:
To get code to run everytime you make a cell change on sheet2, you need to open the class module for sheet2, select Worksheet from the drop-down on the left, and Change for the event.
This code will run everytime you change a cell on sheet2 and in here, you would write code that first checks if the Target argument is in your range like this:
If not Application.Intersect(Target, "A5:25") Then Exit Sub
Next you want to write your code to check if the value is no longer matching, and reset the colours.
HTH
Philip

Resources