3

I am trying to average non-contiguous cells as shown.

Example of what I am trying to do

I am taking the average of columns A and C for each row. I am trying to do the same but with a named range (including columns A and C), because my actual data have thousands of columns and it will be hell to write the formula let alone for the users to understand what is being averaged.

Obviously, I don't understand how indexing a named range works. I expected that index(RangeAC,2) would give me the second row of values in RangeAC. Instead, I get the second row in column A. Trying index(RangeAC,2,2) results in an error.

Is it possible to get this average with a named range or do I need a different approach?

DGenchev
  • 327
  • 3
  • 12

5 Answers5

4

I don't know if I'm missing something, but isnt this as simple as using the Excel intersect operator?:

=AVERAGE(RangeAC 8:8) 

Put in the first row of the named Range data(which seems to be 8:8 in your case), and copy down...

Isnt that the same as the suggested VBA UDF from MrExcel forums?

MacroMarc
  • 3,214
  • 2
  • 11
  • 20
  • this would be the same as `=AVERAGE((A:A,C:C) 8:8)` or `=AVERAGE((A8,C8))` which results in `#ERROR!` when I try it in Google Sheets, but not sure why it works in VBA – Slai Dec 10 '16 at 20:16
  • Not sure what you mean? It's a native Excel formula... I'm not using Google sheets or VBA – MacroMarc Dec 10 '16 at 21:06
  • Never mind .. works in Excel Online `=AVERAGE((A:A,C:C) 2:2)` +1 – Slai Dec 10 '16 at 21:11
  • @MacroMarc Thanks for the reply. I had no idea I can use 'AVERAGE` with a space. I am marking your answer. Thanks again! – DGenchev Dec 11 '16 at 22:17
  • Glad to help. 'Space' is actually the Excel range intersection operator, and can be used in many functions... – MacroMarc Dec 11 '16 at 22:28
  • I tried and it is possible to apply it to MIN as well. However, and that should be in a separate question, is it possible to exclude zero/blank values from the calculation? – DGenchev Dec 12 '16 at 12:53
0

Option 1: Lets say the name of your range is my_data like this one:

![enter image description here

This is the formula to use:

Public Function calculate_avg(rng As Range) As Double

    calculate_avg = WorksheetFunction.Average(Range(rng.Cells(1, 1).Address, Cells(rng.Rows.Count + rng.Cells(1, 1).Row - 1, rng.Columns.Count + rng.Cells(1, 1).Column - 1).Address))

End Function

Option 2: Your named range is the following:

enter image description here

You want the average of the 2. and the 3. column. (C&D). This is how you get it:

Option Explicit

Public Function calculate_avg(rng As Range, Optional l_starting_col As Long = 1, Optional l_end_col As Long = 1) As Double

    Dim my_start    As Range
    Dim my_end      As Range

    Set my_start = Cells(rng.Cells(1, 1).Row, l_starting_col + rng.Cells(1, 1).Column - 1)
    Set my_end = Cells(rng.Cells(rng.Rows.Count, l_end_col).Row, rng.Columns.Count - rng.Cells(1, l_end_col).Column + l_end_col)

    'Debug.Print my_start.Address
    'Debug.Print my_end.Address

    calculate_avg = WorksheetFunction.Average(Range(my_start, my_end))

End Function

You pass as arguments the starting and the end column. Thus something like this: ?calculate_avg([my_test_big],2,3) in the immediate window returns 72,5. The same can be used as an Excel formula. Good luck! :)+

Option 3

Public Function calculate_avg_row(rng As Range, Optional l_row As Long = 1) As Double

    Dim my_start    As Range
    Dim my_end      As Range

    Set my_start = Cells(rng.Cells(l_row, 1).Row, rng.Cells(l_row, 1).Column)
    Set my_end = rng.Cells(l_row, rng.Columns.Count)

    Debug.Print my_start.Address
    Debug.Print my_end.Address

    calculate_avg_row = WorksheetFunction.Average(Range(my_start, my_end))

End Function

This one works like this: calculate_avg_row([test_rng],5) And gives the average of the 5th row of the named range, including all columns of the named range.

Vityata
  • 42,633
  • 8
  • 55
  • 100
  • Thanks for answering. I tried both functions and they give me the average of the first column in my named range (i.e., the average of 1 to 7, which is 4), but my named range contains 1 to 7 in column A and 3 to 9 in column C, so the overall average would be 5. But that's besides the point, I am trying to get the average per row, e.g., for the first row the average of A and C would be 2 (=(1+3)/2). – DGenchev Dec 09 '16 at 12:07
  • On a side note, do you really 'Piya samo belo vino' or just listening to Upsurt? Noticed it on one of the sheets prior to the edit ;) – DGenchev Dec 09 '16 at 12:14
  • I think you did not get the idea of the optional variables in the 2. example. E.g., if you want the average of the second to the forth column, you should write `calculate_avg(my_range,2,4)` In my example, `72.5` is the average of C to D. I like Upsurt :D – Vityata Dec 09 '16 at 12:27
  • Maybe I am still not getting it, but if I have to enter the columns manually, then I don't need the named range. My idea to use a named range was so i would avoid having formulas such as `=average(a2,c2,e2,g2,y2,z2....)`. Instead, I put A2:A10 and C2:C10 and E2:E10, etc. into a named range called Range1. So then I could say average across the first row of Range1, except it doesn't work... – DGenchev Dec 09 '16 at 12:35
  • Probably I do not understand you. My function works only with avg per column. E.g., if you have a named range and you want the average of the values from the second of the named range to the forth column of the named range, it works. What is your idea? You have a named range and you want which average there? – Vityata Dec 09 '16 at 12:39
  • Yes, I don't need a column average, but a row average. Basically, I want a row average of non-adjacent cells. To bypass the problem of selecting 100 non-adjacent cells manually, I created a named range (see my previous comment). Since the named range contains only the columns I am interested in, I assumed I could average the first row of the range, then the second and so on by using `=average(index(range,2)`, understanding this to mean average the second row of 'range', except it doesn't work... – DGenchev Dec 09 '16 at 12:45
  • So, theoretically, if you wanted column average, would my code work? – Vityata Dec 09 '16 at 12:46
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/130222/discussion-between-dgenchev-and-vityata). – DGenchev Dec 09 '16 at 13:22
0

Could you not attach a name to a formula as well? If so,go to the "Formula" tab , "Define Name"and type in the "Refers to" box =Average(A1,C1)). In the name box, you could name it "Average" or whatever you choose to call it.The references would continue to be non-contiguous if you dragged to the right or down the sheet. I am not sure if that is exactly what you're seeking.

Roger H.
  • 326
  • 3
  • 7
0

I appreciate everyone's help. This problem has taken me considerably longer than I was willing to spend on it. Non-contiguous ranges are a nightmare in Excel.

Eric at Mr Excel proposed the most elegant working solution - just one line of VBA.

DGenchev
  • 327
  • 3
  • 12
  • The VBA UDF in the link does the same as @MacroMarc answer (space is used for Intersect in Excel). If you still rather use the UDF, change `ActiveSheet.Rows(r)` to `rng.Worksheet.Rows(r)` because it might be calculated when a different sheet is active. – Slai Dec 10 '16 at 21:27
0

The third parameter of the Index function Reference form can be used to specify the area number:

= AVERAGE( INDEX(RangeAC, ROW()), INDEX(RangeAC, ROW(), , 2) )

or if RangeAC does not start at row 1, something like:

= AVERAGE( INDEX(RangeAC, ROW()-ROW(RangeAC)+1), INDEX(RangeAC, ROW()-ROW(RangeAC)+1, , 2) )
Slai
  • 22,144
  • 5
  • 45
  • 53