Getting unique values in Excel by using formulas only
A roundabout way is to load your Excel spreadsheet into a Google spreadsheet, use Google's UNIQUE(range) function - which does exactly what you want - and then save the Google spreadsheet back to Excel format.
I admit this isn't a viable solution for Excel users, but this approach is useful for anyone who wants the functionality and is able to use a Google spreadsheet.
Solution
I created a function in VBA for you, so you can do this now in an easy way.
Create a VBA code module (macro) as you can see in this tutorial.
- Press Alt+F11
- Click to
Module
inInsert
. - Paste code.
- If Excel says that your file format is not macro friendly than save it as
Excel Macro-Enabled
inSave As
.
Source code
Function listUnique(rng As Range) As Variant
Dim row As Range
Dim elements() As String
Dim elementSize As Integer
Dim newElement As Boolean
Dim i As Integer
Dim distance As Integer
Dim result As String
elementSize = 0
newElement = True
For Each row In rng.Rows
If row.Value <> "" Then
newElement = True
For i = 1 To elementSize Step 1
If elements(i - 1) = row.Value Then
newElement = False
End If
Next i
If newElement Then
elementSize = elementSize + 1
ReDim Preserve elements(elementSize - 1)
elements(elementSize - 1) = row.Value
End If
End If
Next
distance = Range(Application.Caller.Address).row - rng.row
If distance < elementSize Then
result = elements(distance)
listUnique = result
Else
listUnique = ""
End If
End Function
Usage
Just enter =listUnique(range)
to a cell. The only parameter is range
that is an ordinary Excel range. For example: A$1:A$28
or H$8:H$30
.
Conditions
- The
range
must be a column. - The first cell where you call the function must be in the same row where the
range
starts.
Example
Regular case
- Enter data and call function.
- Grow it.
- Voilà.
Empty cell case
It works in columns that have empty cells in them. Also the function outputs nothing (not errors) if you overwind the cells (calling the function) into places where should be no output, as I did it in the previous example's "2. Grow it" part.
Ok, I have two ideas for you. Hopefully one of them will get you where you need to go. Note that the first one ignores the request to do this as a formula since that solution is not pretty. I figured I make sure the easy way really wouldn't work for you ;^).
Use the Advanced Filter command
- Select the list (or put your selection anywhere inside the list and click ok if the dialog comes up complaining that Excel does not know if your list contains headers or not)
- Choose Data/Advanced Filter
- Choose either "Filter the list, in-place" or "Copy to another location"
- Click "Unique records only"
- Click ok
- You are done. A unique list is created either in place or at a new location. Note that you can record this action to create a one line VBA script to do this which could then possible be generalized to work in other situations for you (e.g. without the manual steps listed above).
Using Formulas (note that I'm building on Locksfree solution to end up with a list with no holes)
This solution will work with the following caveats:
Here is the summary of the solution:
- For each item in the list, calculate the number of duplicates above it.
- For each place in the unique list, calculate the index of the next unique item.
- Finally, use the indexes to create a new list with only unique items.
And here is a step by step example:
- Open a new spreadsheet
- In a1:a6 enter the example given in the original question ("red", "blue", "red", "green", "blue", "black")
- Sort the list: put the selection in the list and choose the sort command.
- In column B, calculate the duplicates:
- In B1, enter "=IF(COUNTIF($A$1:A1,A1) = 1,0,COUNTIF(A1:$A$6,A1))". Note that the "$" in the cell references are very important as it will make the next step (populating the rest of the column) much easier. The "$" indicates an absolute reference so that when the cell content is copy/pasted the reference will not update (as opposed to a relative reference which will update).
- Use smart copy to populate the rest of column B: Select B1. Move your mouse over the black square in the lower right hand corner of the selection. Click and drag down to the bottom of the list (B6). When you release, the formula will be copied into B2:B6 with the relative references updated.
- The value of B1:B6 should now be "0,0,1,0,0,1". Notice that the "1" entries indicate duplicates.
- In Column C, create an index of unique items:
- In C1, enter "=Row()". You really just want C1 = 1 but using Row() means this solution will work even if the list does not start in row 1.
- In C2, enter "=IF(C1+1<=ROW($B$6), C1+1+INDEX($B$1:$B$6,C1+1),C1+1)". The "if" is being used to stop a #REF from being produced when the index reaches the end of the list.
- Use smart copy to populate C3:C6.
- The value of C1:C6 should be "1,2,4,5,7,8"
- In column D, create the new unique list:
- In D1, enter "=IF(C1<=ROW($A$6), INDEX($A$1:$A$6,C1), "")". And, the "if" is being used to stop the #REF case when the index goes beyond the end of the list.
- Use smart copy to populate D2:D6.
- The values of D1:D6 should now be "black","blue","green","red","","".
Hope this helps....
This is an oldie, and there are a few solutions out there, but I came up with a shorter and simpler formula than any other I encountered, and it might be useful to anyone passing by.
I have named the colors list Colors
(A2:A7), and the array formula put in cell C2 is this (fixed):
=IFERROR(INDEX(Colors,MATCH(SUM(COUNTIF(C$1:C1,Colors)),COUNTIF(Colors,"<"&Colors),0)),"")
Use Ctrl+Shift+Enter
to enter the formula in C2, and copy C2 down to C3:C7.
Explanation with sample data {"red"; "blue"; "red"; "green"; "blue"; "black"}:
COUNTIF(Colors,"<"&Colors)
returns an array (#1) with the count of values that are smaller then each item in the data {4;1;4;3;1;0} (black=0 items smaller, blue=1 item, red=4 items). This can be translated to a sort value for each item.COUNTIF(C$1:C...,Colors)
returns an array (#2) with 1 for each data item that is already in the sorted result. In C2 it returns {0;0;0;0;0;0} and in C3 {0;0;0;0;0;1} because "black" is first in the sort and last in the data. In C4 {0;1;0;0;1;1} it indicates "black" and all the occurrences of "blue" are already present.- The
SUM
returns the k-th sort value, by counting all the smaller values occurrences that are already present (sum of array #2). MATCH
finds the first index of the k-th sort value (index in array #1).- The
IFERROR
is only to hide the#N/A
error in the bottom cells, when the sorted unique list is complete.
To know how many unique items you have you can use this regular formula:
=SUM(IF(FREQUENCY(COUNTIF(Colors,"<"&Colors),COUNTIF(Colors,"<"&Colors)),1))