2

I have data that I'm moving into a template, and I'm trying to repurpose my vba script I used. Before, the data needed to be transposed into a specific range, but now I want to just move it over without the need to transpose it.

'Write the employee data into the template
a = 0
For k = 2 To UBound(Data, 2)
  Dest.Offset(a, j) = Data(i, k)
  a = a + 1
Next

I assume the dest.offset property is what is causing the transposition, how would I change this to just move the array normally without the transpose?

Rest of script:

Option Explicit

Sub Main()
  Dim Wb As Workbook
  Dim Data, Last
  Dim i As Long, j As Long, k As Long, a As Long
  Dim Dest As Range

  'Refer to the template
  Set Wb = Workbooks("ValidationTemplate.xlsx")
  'Refer to the destination cell
  Set Dest = Wb.Sheets("Employee Core Skills").Range("B3")
  'Read in all data
  With ThisWorkbook.Sheets("Sheet1")
    Data = .Range("DO2", .Range("A" & Rows.Count).End(xlUp))
  End With
  Wb.Activate
  Application.ScreenUpdating = False

  'Process the data
  For i = 1 To UBound(Data)
    'Manager changes?
    If Data(i, 1) <> Last Then
      'Skip the first
      If i > 1 Then
        'Scroll into the view
        Dest.Select
        'Save a copy
        Wb.SaveCopyAs ThisWorkbook.Path & Application.PathSeparator & _
          ValidFileName(Last & "_Assessment.xlsx")
      End If
      'Clear the employees
      Dest.Resize(, Columns.Count - Dest.Column).EntireColumn.ClearContents
      'Remember this manager
      Last = Data(i, 1)
      'Start the next round
      j = 0
    End If
    'Write the employee data into the template
    a = 0
    For k = 2 To UBound(Data, 2)
      Dest.Offset(a, j) = Data(i, k)
      a = a + 1
    Next
    End If
    'Next column
    j = j + 1
  Next
End Sub
nick lanta
  • 602
  • 3
  • 10

1 Answers1

3

If I understand your question correctly...

Dest.Offset(a, j)

Means use the Range referred to by the Range Object called Dest, then offset from there a rows (positive would be down the spreadsheet, negative up the spreadsheet) and j columns (positive to the right, negative to the left).

If you just want to put the data in the Range pointed to by Dest, then simply omit the .Offset() portion like this:

Dest.value2 = Data(i,k).value2

Note: .Value is the default member referred to when you leave it off by referring to just Dest. It's always best to specify and not leave it up to VBA to figure out what you mean. Why use .Value2 instead of just .Value? Read this SO question and the accepted answer.

The transposition is happening here because of the order of a and j.

a = 0
For k = 2 To UBound(Data, 2)
  Dest.Offset(a, j) = Data(i, k)
  a = a + 1
Next
End If
'Next column
j = j + 1

It's really hard to tell because of the unclear variable names.

If you rename your variables like this:

Dim I as Long  --> Dim sourceRow as Long
Dim K as Long  --> Dim sourceCol as Long
Dim A as Long  --> Dim destRow as Long
Dim J as Long  --> Dim destCol as Long

You'll see that's the way they're being currently being used and that what you want to do is swap destRow with destCol.

Rewriting that code with the new variable names gives you:

destRow = 0
For sourceCol = 2 To UBound(Data, 2)
  Dest.Offset(destRow, destCol) = Data(sourceRow, sourceCol)
  destRow = destRow + 1
Next
End If
'Next column
destCol = destCol + 1

and now you can much more easily see that your loop is incrementing your sourceCol and your destRow. If you now change that to:

destRow = 0
For sourceCol = 2 To UBound(Data, 2)
  Dest.Offset(destRow, destCol).Value2 = Data(sourceRow, sourceCol).Value2
  destCol = destCol + 1
Next
End If
'Next column
destRow = destRow + 1

You'll see that the loop is now incrementing both source & dest columns. Now you just need to change the incrementers in the outer loop to update the rows in sync and you should be good.

This is a great object lesson in why good names for code "things" are incredibly valuable. Once I sorted out a, i, j & k, it made it very obvious. It appears you're not the original author of this code, but even if you are, it's OK. Most of us start out with horrible names for stuff then slowly learn over time how valuable good names are. It's well worth it to refactor the code to improve these names and others.

A quick shameless plug for the Rubberduck plugin for the VBE. I'm a huge fan and starting to contribute to the project, as well. It will allow you to refactor your code by intelligently renaming variables. As you can imagine, doing a search & replace for i to sourceRow wsourceRowll gsourceRowve you some sersourceRowously broken code! Rubberduck will avoid that problem and add many, many more features that you'll soon wonder how you ever lived without!

FreeMan
  • 5,660
  • 1
  • 27
  • 53
  • But there is a loop, I guess the OP needs more than 1 cell. – Vityata Oct 05 '18 at 13:26
  • why `value2` instead of just plain `value`? – nick lanta Oct 05 '18 at 13:27
  • 1
    @Vityata that's true. Reading the code & the question, I'm not sure exactly what the OP means by "Transpose". In Excel, one can "Paste Special | Transpose" turning rows into columns (or vice versa). I took "transpose" to mean shifting from the original location pointed to by `Dest`. I guess requesting more clarity would have been appropriate before attempting to answer. – FreeMan Oct 05 '18 at 13:31
  • @nicklanta - please note the comment above and the edit to the post. – FreeMan Oct 05 '18 at 13:32
  • @FreeMan, what I meant by transpose is what you said, paste special / transpose by turning rows into columns. I don't want that, I want a normal paste special. – nick lanta Oct 05 '18 at 13:44
  • @FreeMan, I ran through the steps and it stops on the `dest.value2` line and says error: object required – nick lanta Oct 05 '18 at 13:47
  • @FreeMan, wow, thank you so much, I'll implement that and take these notes with me in the future – nick lanta Oct 05 '18 at 14:26
  • @FreeMan, one more question: there's a part in there that clears contents of everything including the headers `Dest.Resize(, Columns.Count - Dest.Column).EntireColumn.ClearContents` how do I have it preserve the first two rows (headers,etc...) and just clear contents of rows 3 to last row of data? – nick lanta Oct 05 '18 at 14:45
  • @nicklanta note the leading, missing parameter in `.Resize()`. That's the row parameter (put the cursor just before that `,` and hit `Ctrl-i`). Set that to indicate where you want your `Resize.ClearContents` to happen – FreeMan Oct 05 '18 at 14:49
  • @FreeMan, I figured it was (3,columns.count) but it appears that even adding that causes the whole column to clear contents due to the `.entirecolumn.clearcontents` part, is there a way to edit that out to just ignore the first two rows? I figured a `dest.offset(2).resize` etc... thing would work, but it doesnt – nick lanta Oct 05 '18 at 14:51
  • ah, yeah... remove the `.EntireColumn` portion of that line. that should give you what you're after. – FreeMan Oct 05 '18 at 14:55
  • @FreeMan, I'm so sorry, I promise the last question. it preserves the header, fills in the first row from the array, but before it can move to the next employee row, it stops with a subscript out of range on this line: `Dest.Offset(destcol, destrow) = Data(sourcerow, sourcecol)` I had to change around the `offset(destcol,destrow)` part because it was still transposing – nick lanta Oct 05 '18 at 14:58
  • Best to ask that as a new question with a post of your current code. It's hard to know exactly what your code is now - I've probably got one thing in my head while you've got something else actually written down. – FreeMan Oct 05 '18 at 15:00
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/181356/discussion-between-nick-lanta-and-freeman). – nick lanta Oct 05 '18 at 15:23