I have been searching for few hours and I couldnt find any solution for this problem.
As you can see on the image I have 3 columns and 2 rows. My goal is to sum the cost row (it has line breaks) or split equipment and cost columns into 3 smaller rows. Is this possible?
Something like this in VBA will work:
Function SumLines(ByVal str As String) As Long
Dim arr() As String
arr = Split(str, Chr(10))
For a = 0 To UBound(arr)
SumLines = SumLines + CLng(arr(a))
Next
End Function
However, this will only work if you don't have any characters other than digits and Chr(10)s (new lines).
You then use this in your worksheet, e.g.:
=SumLines(A1)
Unfortunately there's not a particularly clean way to achieve this (to my knowledge). Here are a couple of things you could try though:
Method 1 - worksheet solution
If your first cost cell is in A1 then place the cursor in cell B1 and create a new named range using the following formula:
=EVALUATE(SUBSTITUTE(A1,CHAR(10),"+"))
You can then type the name of the named range into cell B1 and you'll get the sum as expected. Unfortunately you have to create a named range for this because EVALUATE isn't available as a worksheet function - only a named range function and also available in VBA.
I called my named range "eval". You can drag this formula down and it will fill down, always evaluating the cell to it's left.
Method 2 - VBA solution
You can use some simple VBA. Paste this into a new module and then use this formula on the worksheet like this:
=SumAlt(A1)
will return 600 in your example, if A1 contained your 100 200 300
Function SumAlt(s As String) As Long
SumAlt = Evaluate(Replace(s, Chr(10), "+"))
End Function
Related
In Excel formula become often very long and, consequently, unreadable. For example my formula looks like this:
=PERCENTRANK([vol];[#vol])-PERCENTRANK([pos];[#pos])
I would like to write just
=SCORE("vol", "pos")
How can I create a user defined function from the original worksheet formula?
You can do this relatively easily using VBA's WorksheetFunction. The most difficult part is actually getting the column of the [#Range] so you don't have to enter it - but that's not too complicated either.
In the VBE, create a new standard module and paste the following UDF:
Public Function SCORE(vol As Range, pos As Range) As Double
' We need to get the entire column of the table for each argument
Dim tbl As ListObject, volRng As Range, posRng As Range
Set tbl = vol.ListObject
Rem -> Table columns are relative to the table - not the worksheet
Set volRng = tbl.Range.Columns(vol.Column - tbl.Range.Cells(1).Column + 1)
Set posRng = tbl.Range.Columns(pos.Column - tbl.Range.Cells(1).Column + 1)
With Application.WorksheetFunction
SCORE = .PercentRank(volRng, vol) - .PercentRank(posRng, pos)
End With
End Function
You have to keep in mind that table column numbers are not always the same as the worksheet's (if your table doesn't start in column A). So you essentially have to offset by the number of worksheet columns by subtracting the column from your arguments vol and pos from the column number of the first cell of the entire table tbl.range.cells(1). Then you add one because columns numbers in VBA is "base 1".
You will still have to send the range of the individual cell - so using string arguments are not going to do well here. With all that being said, your new worksheet formula would look like:
=SCORE([#vol],[#pos])
or
=SCORE([#vol];[#pos])
depending on if you separate arguments using , or ;.
I want to be able to create a list of matching elements from two columns in different worksheets.
Let me provide a mock example:
I have two lists of elements, in this case boys names and girls names. Those will be placed in different sheets. In the figure below, for simplicity, they are placed in different columns (discontinuos range). I want the formula to generate the list in cells A3:A14 (list all elements in the discontinuous range which match containing the text "jo".
I've learned that the best way to provide such discontinuous range to a formula is by defining a named range.
So far, what I got is:
{IF(
MATCH(
INDEX(Named_Range,
SMALL(IF(Named_Range="*"&$A$3&"*",
ROW(Named_Range)-ROW(INDEX(Named_Range,1,1))+1),ROW()-1)),
'(Names)'!C:C,
0),
INDEX(Named_Range,
SMALL(IF(Named_Range="*"&$A$3&"*",
ROW(Named_Range)-ROW(INDEX(Named_Range,1,1))+1),
ROW()-1)),
"")
}
Named_Range is declared as
=D9:D13,F3:F6
The small function returns the nth element matching the criteria. It should also MATCH one of the names in (Names)!C:C. If so, I get the value of that cell. For the sake of simplicity, consider that '(Names)'!C:C contains all names, so it will always be true.
This formula worked for me using a single column as the range. However, I cannot evaluate the formula using the discontinuous range without Excel crashing, so I'm looking for a piece of advice on how to get it right.
Thanks.
Perhaps the best way to deal with a discontinuous range is to make it continuous...?
Your problem can be simplified a lot with a small VBA function. This function takes a discontinuous named range and returns a single continuous column containing all the same values. That way you can use your INDEX/MATCH/SMALL etc formulas in the normal way
Function Arrange(rng As Range) As Variant
Dim temp As Variant
Dim i As Long
Dim r As Range
ReDim temp(1 To rng.Cells.Count)
i = 1
For Each r In rng
temp(i) = r.Value
i = i + 1
Next r
Arrange = Application.Transpose(temp)
End Function
After you have added this code to a new module in your VBA editor you will be able to use it like this on the worksheet:
=INDEX(ARRANGE(Named_Range),1)
To get the first element, for example.
After 3 hours of searching I still didn't find an answer, here is what I am trying to do:
I am trying to fill with green any row that has WBS in it and with Red any row that has ACT in it and Blue any row that has EPR in it. It works for the first formula then when I try to add the second one every thing get messed up.
what i have understood is that you need to search a keyword in a row and if its found in any cell of that row then color it.
May be we can do it with conditional formatting but i have another idea. We can create a simple search function in Excel VBA. Something like this:
=search_row(A1:F1,"EPR")
The function will return 1 if EPR is found in any cell of specified row. Now if you create two different columns at the end of data columns, name first with WPS and second with EPR and write this function in it. Like
G1 =search_row(A1:F1,"WPS")
H1 =search_row(A1:F1,"EPR")
Drag it to end. Now sort the columns. First for WPS from higher to lower. Then color all rows having 1 in a single select. Similarly do the same with EPR (H1) column.
To use this function you can download the macro file from the following URL:
http://asimishaq.com/myfiles/SearchHighlight.xlsm
Now to run it first of all enable macros, and then re-open your data file and then open this macro file. As long as this macro file is opened you can use this function. Following is the VBA code if you want to create the macro yourself:
Function search_row(sRow As Range, Keyword As String)
Dim i As Integer
Dim Found As Integer
For i = 1 To sRow.Columns.Count
If InStr(1, LCase(sRow.Cells(1, i)), LCase(Keyword)) > 0 Then
search_row = 1
End If
Next
End Function
I had a go at making a function similar to asim-ishaq to determine if your search term exists in the row for fun :) then tried to apply it to highlighting rows, turns out I dont know how to use conditional formatting very well! Figured it out in the end, hopefully I've explained it well enough.
With this you will have to have (one) extra column at the end of your data to contain the result.
It might be possible to not require the extra column by putting the function inside the conditional formatting, however I couldn't get it to work (didn't try very hard). This isn't a great loss as it's much simpler to edit the formula if its on the workbook, instead of having to go through each conditional rule to edit it, should you need to edit it in the future.
To get the formatting to work you will need to create a number of rules (one per keyword)
You want to create a rule of the type shown below, in the formula box you need something along the lines of: =INDIRECT("D" & ROW())=0 where D is the column containing the result of the function below and 0 is the index of the keyword you're highlighting.
In my example, the formula in the D Column is: =SearchRow(An:Cn,"ABS","KBS","JBS") (where n is the row the formula is on)
Set the formatting as desired then press OK, when you return to the rule manager you will need to update the Applies to value, which should be a range that covers all the data you want to highlight. In my example it was $A$1:$C$3
My function below takes 2+ Arguments, The first is the range to search. The second (and any subsequent ones) are search terms.
The function will return a number. -1 for no matches and 0+ for the found search term. The number depends on the position in the arguments.
A1 = "ABS"
B1 = "SBA"
A2 = "SBA"
B2 = "ABS"
A3 = ""
B3 = ""
C1 = "=SearchRow(A1:B1, "ABS", "SBA")"
C2 = "=SearchRow(A2:B2, "ABS", "SBA")"
C3 = "=SearchRow(A3:B3, "ABS", "SBA")"
C1 > 0
C2 > 1
C3 > -1
The function will always return the first result, searching left to right comparing each cell to the Keywords in order. Using my example, if a cell contained "SBA ABS" the result would be 0 (for ABS). I guess your cells will probably only contain one keyword though so this shouldn't be a problem?
Public Function SearchRow(ByVal Row As Range, ParamArray Keyword() As Variant) As Integer
Dim Column As Integer
Dim Value As String
Dim Index As Integer
Dim Result As Integer
For Column = 1 To Row.Columns.Count
Value = LCase(Row.Cells(1, Column))
Result = -1
For Index = LBound(Keyword) To UBound(Keyword)
If InStr(1, Value, LCase(Keyword(Index))) > 0 Then
Result = Index
Exit For
End If
Next Index
If Result > -1 Then
Exit For
End If
Next Column
SearchRow = Result
End Function
I've searched the web but I can't find anything specific for this.
I have column A as below, I need to search this column and find out how many occurrences there are of the data in column B, in the example below there a 4 (70011x3 + 70014x1).
A B
h323:70011 70011
70007 70012
70011 70013
h323:70014 70014
sip:70011#domain.com 70015
What formula would I need to use in Excel?
Thanks in advance
... I don't know if there's a simple way to do this with a single worksheet function, but I could think of 2 methods I would use to accomplish this (and would love to see if any person could figure out how to do this in a single, simple, worksheet function I couldn't think of).
Either way, my solutions would be:
1) Use Array Formulas:
This would look as follows:
A B C
h323:70011 70011 {=SUM(--ISNUMBER(FIND(B1,$A$1:$A$5,1)))}
70007 70012 {=SUM(--ISNUMBER(FIND(B2,$A$1:$A$5,1)))}
...etc
Note that for this solution, you have to type it in as an array formula (Hit ctrl+shift+enter) at the end, but when you drag down column C and sum it up, you will get the correct total.
The challenge with this one is that it doesn't really give you the answer in one cell.
2) Use a Custom VBA Function (My Preferred method):
You can write your own VBA function to do this VERY EASILY.
The one I created was:
Function MyFunc(CriteriaRng As Range, SearchRange As Range) As Double
Dim CriteriaCl As Range
Dim SearchCl As Range
Dim RunningTotal As Double: RunningTotal = 0
For Each CriteriaCl In CriteriaRng
For Each SearchCl In SearchRange
If InStr(1, SearchCl.Value, CriteriaCl.Value) > 0 Then RunningTotal = RunningTotal + 1
Next SearchCl
Next CriteriaCl
MyFunc = RunningTotal
End Function
All you can then do is in any cell type in =myfunc(B1:B5,A1:A5) and you will get the right answer.
Hope this helps!
the function COUNTIF takes wildcards.
with excel 2007, you can simply reference the whole column:
=COUNTIF(A:A,"*"&B1&"*")
with 2003 or lower, you have to put the range in as cell references
=COUNTIF(A1:A2000,"*"&B1&"*")
note that numbers will have to be formatted as text, or you can add in the countif to cover numbers
=COUNTIF(A:A,"*"&B1&"*")+COUNTIF(A:A,B1)
You can then use a SUM on the column to get the total.
I'm looking for the most elegant way to count the same number values in a noncontiguous range (I'll refer to it as just 'range'). This is the range:
=$C$2:$C$31,$E$2:$E$31,$G$2:$G$31,$I$2:$I$31,$K$2:$K$31,$M$2:$M$31,$O$2:$O$31,$Q$2:$Q$31,$S$2:$S$7
These are the parameters:
The range contains non-adjacent columns.
The columns differ in height.
The cells in the range are either empty or contain integers.
I'm checking for how many cells equal '1', how many equal '2' etc. in the range. (Not in one go, but in seperate formulas).
I've used a named range to reference the range. I'd really like to use this named range in the formula, in one way or another.
I hope I've given you enough info... Thanks in advance!
I agree with Kartik that a VBA solution is required. However the solution offered is a little inefficient in that it loops over every cell in the ranged passed into the function. It also limits the key parameter to a range reference, and can only count up to 32767 matches. Here's an alternative addresses these shortcomings
Function CountIf_N(rng As Range, key As Variant) As Variant
Dim r As Range
Dim count As Long
count = 0
For Each r In rng.Areas
count = count + WorksheetFunction.CountIfs(r, key)
Next
CountIf_N = count
End Function
Note: assumes Excel 07 or later. If using with an ealier version replace CountIfs with CountIf
One approach is to use excel built in function Countif, but it won't work with non-contigous range. The other way (the easy way) will be to use VBA to create your own custom function, and then use it in excel.
I've presented that technique here.
Goto visual basic editor in excel by pressing Alt+F11, in the project window insert a new module and paste the below code:
Function countif_n(rng As Range, key As Range) As Integer
Dim count As Integer
count = 0
For Each cell In rng
If cell.Value = key.Value Then
count = count + 1
End If
Next cell
countif_n = count
End Function
Here rng is your non-contigous range, and key represent the "range"(cell) which contains the value you want to count. For eg., to check for 1 enter 1 in any cell lets suppose "F2", and your non-contigous range is "testrange"
Then use the above function by entering the following in any blank cell:
=countif_n(testrange, F2)
Although COUNTIF can't handle non-contiguous ranges some functions can, for example RANK and COUNT so for a range called Range this formula will give the number of instances of a number in Z2 within Range
=IFERROR(COUNT(Range)-SUM(RANK(Z2,Range,{1,0}))+2,0)
assumes Excel 2007 or later but can be amended to work in earlier versions
This doesn't quite work if there's stuff below S7 that can't be counted, but you may be able to modify. It also doesn't incorporate the named range.
=SUM(IF(MOD(COLUMN(A2:S31),2)=0,IF(A2:S31=2,1,0)))
This example counts the number of 2's.
This needs to be array-entered with ctrl-shift-enter. It's based on the fact that you're counting in every other column, at least in your example. Also, although you mention the columns are different heights, it looks like all except S are the same height. So maybe there's a way to work around that.