How to count distinct values in Excel - excel

Input
I need Summary like below
I am looking for distinct no of account here instead of duplicate.

You can FILTER the original data and then count the number of unique instances.
Try =COUNT(UNIQUE(FILTER($A$2:$A$10, $B$2:$B$10=$D2)))
Here I assume that the original data is in cells A2:B10, and that the criteria for the filtering is in column D.

I have updated my answer to work for Office 2007 and mixed #Rory's comment to original post with my OFFSET part of my previous Office 365 solution.
Formula
Plase the following formula in E2:
=SUM(1/COUNTIFS(OFFSET($A$3,MATCH(D3,$A$3:$A$12,0)-1,1,COUNTIF($A$3:$A$12,D3),1),OFFSET($A$3,MATCH(D3,$A$3:$A$12,0)-1,1,COUNTIF($A$3:$A$12,D3),1)))
Explanation
The OFFSETpart provides a list of consecutive rows that feature the Acc No and belong to the same Br code. It uses MATCHto determine the first occurance of the given Br code. As the anchor cell for the formula is the cell with the first content ($A$3), I subtract 1 from the MATCH result. To determine the height, I use a COUNTIF statement, that counts how many rows feature the current Br code.
The cell range provided by OFFSET is then used as input for #Rory's COUNTIFS solution.

The text and non-text (numeric) unique and distinct values in the column are quickly listed separately using VBA macro.
enter image description here
Sub GetCountDistinctValues()
Dim sayi As Long, rang As Range
With CreateObject("Scripting.Dictionary")
For Each rang In Range("A2:A" & Cells(Rows.Count, "A").End(xlUp).Row)
If rang <> Empty Then
If Not .Exists(rang.Value) Then
.Add rang.Value, Nothing
If IsNumeric(rang.Value) Then sayi = sayi + 1
End If
End If
Next
Range("C2").Value = .Count - sayi
Range("C3").Value = sayi
End With
End Sub
Source : Find count of unique-distinct values

Related

Excel VBA to compare string of one column to string of second column

I'm trying to create a macro that will compare the first 4 characters of one column to the first 4 characters of another column in the same row and then mark that row as either Match or No Match.
I did some research and found an Excel formula (=IF(ISNA(MATCH(LEFT(A2,4)&"*",B2:B2,0)),"No Match","Match") which works but I'm not sure how to convert this to VBA. The spreadsheets I'm working with can vary in row length from day to day but they would always have the same number of columns. So I need to be able to: compare column C to column F and write the Match / No Match outcome to column G regardless of the number of rows on the spreadsheet.
Here is an example of the spreadsheet I'm working with that shows the outcome of using the Excel formula.
Any help / suggestions you can provide would be appreciated.
]1
You can use simplified formula and convert it to values if needed (works for active sheet).
Sub CompareLeft()
Dim LRow As Long
LRow = Cells(Rows.Count, "A").End(xlUp).Row
With Range("c2:c" & LRow) '<-- Adjust result column
.FormulaR1C1 = "=IF(LEFT(RC1,4)=LEFT(RC2,4),""Match"",""No Match"")"
.Value = .Value '<-- Optional - convert formula to values
End With
End Sub

VBA to extract unique values from list and count them on separate page

Ok, this has to be the easiest question ever, but I've been searching for awhile and can't figure this out. I have a very long list of values on sheet "Page1_1" (shtData) which I need to use to generate a list of unique values, along with a count of each unique value, on "Numbers". It's very simple to do manually by just copying to "Numbers" (shtNumbers) and removing duplicates, but the countif formula I use is very memory intensive, and bogs it all down. I have code to provide the unique list, but trying to get the count of each item is stumping me
Put simply: I need code to generate a list of unique values from "Page1_1" (shtData) A2:end of data, and put that list starting on "Numbers" (shtNumbers) A2 and down, then count occurrences and list the count in B2 and down.
current code:
shtData.Range("A2:A65536").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=shtNumbers.Range("A2"), Unique:=True
That code generates the list for me perfectly. I'd post what I've got for the count part, but it doesn't work at all, so I doubt it'd be helpful at all.
Thanks!
Try this:
With shtNumbers
With .Range(.Range("B2"),.Range("A2").End(xlDown).Offset(,1))
.FormulaR1C1 = "=COUNTIF(Data!C[-1],RC[-1])" 'change data to actual sheet name
End With
End With
Give this a try:
Sub SuperSimpleFrequencyTable()
Dim C As Range, A As Range, B As Range
Set A = Sheets("Page1_1").Range("A:A")
Set B = Sheets("Numbers").Range("A:A")
A.Copy B
B.RemoveDuplicates Columns:=1, Header:=xlNo
Set C = B.SpecialCells(xlCellTypeConstants).Offset(0, 1)
With C
.Formula = "=countif(Page1_1!A:A,A1)"
.Value = .Value
End With
End Sub
It will not leave formulas in the Numbers sheet.

Creating a "search" function in MS Excel

I have a list of >100,000 diagnosis codes in a .XLS document and need to extract from this all codes that are relevant to a number of specific diseases.
What I would like to be able to do is include all 100,000 diagnostic codes in Column A, diagnostic labels in column B, and then have a "search term" cell (e.g. C1) in which I can write a word such as "fracture".
I would then like all the diagnostic codes including the string "fracture" to appear in column D.
Is there a simple way of doing this in Excel? I have looked online without much success but this might be because I'm not certain where to start. Conditional formatting hasn't helped as it's still unmanageable to scroll through 100,000 codes even if they are highlighted nicely.
Any initial thoughts or tips as to what I could try searching for would be very welcome.
Sample dataset:
238 Fracture of proximal humerus
202 Aortic stenosis
990 Chronic obstructive pulmonary disease
302 Hip fracture
182 Recurrent fractures
094 Marfan syndrome
298 Diabetic retinopathy
We can use a helper column to find the matching rows. In E1 enter:
=MATCH("*" & $C$1 & "*",B:B,0)
and in E2 enter:
=IFERROR(MATCH("*" & $C$1 & "*",INDEX(B:B,E1+1):INDEX(B:B,999999),0)+E1,"")
and copy down. Column E tells us where the matches are.. Then in D1 enter:
=IFERROR(INDEX(A:A,E1),"")
and copy down:
This is a fairly standard way to do a keyword search.
I realize you didn't ask for a filter but if you are open to a slightly different solution this seems to work well. Column A title and values should start at cell A2. Then type your search term in cell B1. It will also filter with wildcards and is case insensitive (i.e. show fracture, Fracture, fractures, Fractures, fractured, Fractured).
Option Explicit
Sub Filter()
Dim MyArray() As Variant
Dim MyNewArray() As Variant
Dim i As Long
Dim item As Variant
Dim FilterRange As Range
With ActiveSheet
Set FilterRange = .Range(.Cells(2, 1), .Cells(.Rows.Count, 1).End(xlUp))
MyArray = Application.Transpose(FilterRange)
i = 0
For Each item In MyArray
If UCase(item) Like "*" & UCase(Range("B1")) & "*" Then
ReDim Preserve MyNewArray(i)
MyNewArray(i) = item
i = i + 1
End If
Next item
.Range(FilterRange.Address).AutoFilter Field:=1, Criteria1:=MyNewArray(), Operator:=xlFilterValues
End With
End Sub
Additionally, you could add the following in the Worksheet object so you don't have to click a button to run the macro:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Range("B1")) Is Nothing Then
Call Filter
End If
End Sub
Honestly, you can achieve the same thing with Filter > Text Filters > Custom Filter. You can use wildcards, too. :)
Let's say you want to search the term contained in C1 in column B.
You can try using this in A
=IF(C1<>"",IFERROR(FIND(C1,B1,1),0),0)
This will return a number if the text in C1 is present, else a 0.
You can then set D to be
=IF(A1>0,B1,"")
You will obtain this
I am putting the string to be searched for in the first row.
In row 2, I do a string match to get the first instance of a match for C1 in column A.
C2 =INDEX($A:$A,MATCH("*"&C1&"*",$A2:$A$100,0)+1)
Then find the next match starting from the array with row that matches C2 as the first row. I am fixing the last row as A100 which you can change.
C3 =INDEX($A:$A,MATCH("*"&$C$1&"*",INDIRECT("A"&MATCH(C2,$A:$A,0)+1&":A100"),0)+MATCH(C2,$A:$A,0))
Copy the formula down as required. Then copy columns across as required.
You can wrap the formula using IFERROR to suppress N/As.
You can also used an advanced filter in Excel by going to Data|Advanced:-
Note that the column headers in C1 and D1 must match the column headers in A1 and B1.
You can also adopt a DIY approach with:-
=IFERROR(INDEX(B:B,SMALL(IF(ISNUMBER(SEARCH($H$2,$B$1:$B$100000)),ROW($B$1:$B$100000)),ROW(1:1))),"")
assuming the search term is in H2, starting in say J2 and pulled down as necessary. This may be a little slow with 100K terms but is usable. Must be entered as an array formula with CtrlShiftEnter

VBA code to recopy multiple cells if a specific cell contains a specific text

I'm new here and I apologize in advance in my question isn't clear... I couldn't find the answer after some research...
I'm looking for a way to go through all the cells of column "R" and if one cell on a given row contains "Y", then the values of cells at columns "W","X" and "Y" will take the same value as the columns "F","G" and "H" (always at the same row).
The goal is to have a button that will execute the VBA code in order to do this (instead of having to copy/paste all the time).
Thank you very much in advance for your help.
A poor ignorant but motivated VBA beginner...
Here is VBA which will do what you want. It takes advantage of the replacement operation being cells that are next to each other by using Resize.
Highlights
Iterates through each cell in column R. I used Intersect with the UsedRange on the sheet so that it only goes through cells that have values in them (instead of all the way to the end).
Checks for "Y" using InStr.
Replaces the contents of columns WXY with values from columns FGH. Since they are contiguous, I did it all in one step with Resize.
Code:
Sub ReplaceValuesBasedOnColumn()
Dim rng_search As Range
Dim rng_cell As Range
'start on column R, assume correct sheet is open
Set rng_search = Range("R:R")
For Each rng_cell In Intersect(rng_search, rng_search.Parent.UsedRange)
'search for a Y, case sensitive
If InStr(rng_cell, "Y") > 0 Then
'update the columns as desired
'takes advantage of cells being next to each other
Range("W" & rng_cell.Row).Resize(1, 3).Value = Range("F" & rng_cell.Row).Resize(1, 3).Value
End If
Next rng_cell
End Sub
I tested it on my end, and it works, producing the following after running:

Excel Min Date in a given range

I have an Excel file with multiple columns. If you observe the attached image the 1st column is coupons (repeated with different settlement dates). I need to write a macro which will loop through the file, and find one record for each coupon with the minimum date of all the dates that particular coupon has. For example, coupon 2 has 4 records in the attached image. I should delete three off them, and have only one record with the earliest date among those four.
Can someone please provide me an example?
One possibly is to use a temporary array formula. Assuming field Coupon is column B and Date is column C then in the next free column, say column N use {=IF(C2=MIN(IF($B:$B=B2,$C:$C)),TRUE,FALSE)}
Then use an advanced filter to filter on Coupon and TRUE in Column N. In this example I've set up the criteria and output from column Q
Eg VBA Code example
Sub test()
Dim rng As Range, strR1c1 As String
'identify minimum date using array formula
With Sheet1
.Range("N1").Value = "Temp Header"
'array formula = {=IF(C2=MIN(IF($B:$B=B2,$C:$C)),TRUE,FALSE)}
.Range("N2").FormulaArray = "=IF(RC[-11]=MIN(IF(C2=RC[-12],C3)),TRUE,FALSE)"
strR1c1 = .Range("N2").FormulaR1C1
Set rng = .Range("N2:N" & .Range("B" & .Rows.Count).End(xlUp).Row)
rng.Formula = strR1c1
rng.FormulaArray = rng.FormulaR1C1
'Advanced Filter criteria requirements to new range
.Range("B1:N11").AdvancedFilter Action:=xlFilterCopy, CriteriaRange:=.Range( _
"Q1:AC2"), CopyToRange:=.Range("Q5:AC5"), Unique:=False
'tidy up - clear array formula
.Range("N:N").ClearContents
End With
End Sub

Categories

Resources