Create a drop down list containing only unique distinct alphabetically sorted text values using excel array formula
Question:
How do I create a drop down list with unique distinct alphabetically sorted values?
Answer:
Table of contents
Sort values using array formula
Array formula in cell B2
How to create an array formula
- Select cell B2
- Type above array formula
- Press and hold Ctrl + Shift
- Press Enter once
- Release all keys
How to copy array formula
- Select cell B2
- Copy (Ctrl + c)
- Select cell range B3:B6
- Paste (Ctrl + v)
Explaining array formula in cell B2
=INDEX(List, MATCH(0, IF(MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1))=(COUNTIF(List, ">"&List)+1), 0, 1), 0))
Step 1 - Convert text to numbers
=INDEX(List, MATCH(0, IF(MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1))=(COUNTIF(List, ">"&List)+1), 0, 1), 0))
COUNTIF(range,criteria) counts the number of cells within a range that meet the given condition
COUNTIF(List, ">"&List)+1
becomes
COUNTIF({"DD";"EE";"FF";"EE";"GG";"BB";"FF";"GG";"DD";"TT";"FF";"VV";"VV";"FF"}, ">"&{"DD";"EE";"FF";"EE";"GG";"BB";"FF";"GG";"DD";"TT";"FF";"VV";"VV";"FF"})+1
becomes
{11;9;5;9;3;13;5;3;11;2;5;0;0;5}+1
becomes
{12;10;6;10;4;14;6;4;12;3;6;1;1;6}
Step 2 - Identify previous unique text values above current cell
=INDEX(List, MATCH(0, IF(MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1))=(COUNTIF(List, ">"&List)+1), 0, 1), 0))
COUNTIF(range,criteria) counts the number of cells within a range that meet the given condition
NOT(COUNTIF($B$1:B1, List))
becomes
NOT(COUNTIF("Unique list sorted alpabetically", {"DD";"EE";"FF";"EE";"GG";"BB";"FF";"GG";"DD";"TT";"FF";"VV";"VV";"FF"}))
becomes
NOT({0;0;0;0;0;0;0;0;0;0;0;0;0;0})
becomes
{1;1;1;1;1;1;1;1;1;1;1;1;1;1}
Step 3 - Calculate maximum number in array
=INDEX(List, MATCH(0, IF(MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1))=(COUNTIF(List, ">"&List)+1), 0, 1), 0))
MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1))
becomes
MAX({1;1;1;1;1;1;1;1;1;1;1;1;1;1}*({12;10;6;10;4;14;6;4;12;3;6;1;1;6})
and returns 14.
Step 4 - Convert maximum number into Boolean value
=INDEX(List, MATCH(0, IF(MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1))=(COUNTIF(List, ">"&List)+1), 0, 1), 0))
IF(MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1))=(COUNTIF(List, ">"&List)+1), 0, 1)
becomes
IF(14={12;10;6;10;4;14;6;4;12;3;6;1;1;6}, 0, 1)
and returns this array:
{1;1;1;1;1;0;1;1;1;1;1;1;1;1}
Step 4 - Return the relative position of an item in an array
=INDEX(List, MATCH(0, IF(MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1))=(COUNTIF(List, ">"&List)+1), 0, 1), 0))
MATCH(lookup_value;lookup_array; [match_type]) returns the relative position of an item in an array that matches a specified value
MATCH(0, IF(MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1))=(COUNTIF(List, ">"&List)+1), 0, 1), 0)
becomes
MATCH(0, {1;1;1;1;1;0;1;1;1;1;1;1;1;1}, 0)
and returns value 6.
Step 5 - Return a value of the cell at the intersection of a particular row and column
INDEX(array,row_num,[column_num]) returns a value or reference of the cell at the intersection of a particular row and column, in a given range
=INDEX(List, MATCH(0, IF(MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1))=(COUNTIF(List, ">"&List)+1), 0, 1), 0))
becomes
=INDEX(List, 6)
becomes
=INDEX({"DD";"EE";"FF";"EE";"GG";"BB";"FF";"GG";"DD";"TT";"FF";"VV";"VV";"FF"}, 6)
and returns value BB.
Create a dynamic named range
- Click "Formulas" tab
- Click "Name Manager"
- Click List
- Type =OFFSET(Sheet1!$A$2, 0, 0, COUNT(IF(Sheet1!$A$2:$A$1000="", "", 1)), 1) in "Refers to:" field.
- Click "Close" button
Named range
List (dynamic)
What is named ranges?
How to create a drop down list with values updated dynamically in excel 2007
- Click Data tab
- Click Data validation button
- Click "Data validation..."
- Select List in the "Allow:" window. See picture below.
- Type =OFFSET($B$2, 0, 0, COUNT(IF($B$2:$B$1000="", "", 1)), 1) in the "Source:" window
- Click OK!
Download example workbook
Create-a-drop-down-list-containing-only-unique.xls
(Excel 97-2003 Workbook *.xls)
Functions in this article:
IF(logical_test;[value_if:true];[value_if_false])
Checks whether a condition is met, and returns one value if TRUE, and another value if FALSE
INDEX(array,row_num,[column_num])
Returns a value or reference of the cell at the intersection of a particular row and column, in a given range
SMALL(array,k) returns the k-th smallest row number in this data set.
ROW(reference) returns the rownumber of a reference
MATCH(lookup_value;lookup_array; [match_type])
Returns the relative position of an item in an array that matches a specified value
COUNTIF(range,criteria)
Counts the number of cells within a range that meet the given condition
COUNT(value1;[value2])
Counts the number of cells in a range that contain numbers
OFFSET(reference,rows,cols, [height],[width])
Returns a reference to a range that is a given number of rows and columns from a given reference
Sort values using vba
Array formula in cell B2:B8000:
How to create array formula
- Select cell range B2:B8000
- Type array formula above
- Press and hold Ctrl + Shift
- Press Enter once
- Release all keys
VBA code
You can find the selectionsort function here: Using a Visual Basic Macro to Sort Arrays in Microsoft Excel
Function FilterUniqueSort(rng As Range)
Dim ucoll As New Collection, Value As Variant, temp() As Variant
ReDim temp(0)
On Error Resume Next
For Each Value In rng
If Len(Value) > 0 Then ucoll.Add Value, CStr(Value)
Next Value
On Error GoTo 0
For Each Value In ucoll
temp(UBound(temp)) = Value
ReDim Preserve temp(UBound(temp) + 1)
Next Value
ReDim Preserve temp(UBound(temp) - 1)
SelectionSort temp
FilterUniqueSort = Application.Transpose(temp)
End Function
Function SelectionSort(TempArray As Variant)
Dim MaxVal As Variant
Dim MaxIndex As Integer
Dim i, j As Integer
' Step through the elements in the array starting with the
' last element in the array.
For i = UBound(TempArray) To 0 Step -1
' Set MaxVal to the element in the array and save the
' index of this element as MaxIndex.
MaxVal = TempArray(i)
MaxIndex = i
' Loop through the remaining elements to see if any is
' larger than MaxVal. If it is then set this element
' to be the new MaxVal.
For j = 0 To i
If TempArray(j) > MaxVal Then
MaxVal = TempArray(j)
MaxIndex = j
End If
Next j
' If the index of the largest element is not i, then
' exchange this element with element i.
If MaxIndex < i Then
TempArray(MaxIndex) = TempArray(i)
TempArray(i) = MaxVal
End If
Next i
End FunctionWhere to copy vba code?
- Press Alt + F11
- Insert a module into your workbook
- Copy (Ctrl + c) above code into the code window
Download excel 97-2003 *,xls file
Create-a-drop-down-list-containing-only-unique_vba.xls
Related posts:
Create unique distinct list sorted based on text length using array formula in excel
Create a drop down list containing alphabetically sorted values in excel
Create a unique distinct alphabetically sorted list, extracted from a column in excel
Unique distinct list from a column sorted A to Z using array formula in excel
Filter unique distinct list sorted based on sum of adjacent values using array formula in excel






















I encountered an issue when using Excel 2007 where upon saving the workbook as an Excel Workbook (not 97-2003) the embedded count(if( ...)) formula causes only the first item in the drop down list to appear. This only happens upon opening the workbook and if you select data validation on the cell the issue is resolved. However, upon saving and reopening the problem reappears. The only workaround if to either remove the function or keep the workbook in 97-2003 format.
Josh, thanks for bringing this to my attention. I´ll try to solve this issue.
I want the drop down box to be on a different worksheet. But EXCEL won't allow OFFSET without having it all on one worksheet.
Is there some other way to have the lists on one sheet, get unique values and sort them, then reference them from a drop down on another worksheet? To make matter more fun, I need the ranges to be dynamic as the user may be adding new records.
Thanks!
Dianne
I have re-created the above formula but would like to create a range that is larger than the current data so that the unique list picks up all new data. Currently my unique list repeats the last line of data several times because the range name extends beyond it. Can this be done?
Thanks
Keels
Dianne,
I want the drop down box to be on a different worksheet. But EXCEL won't allow OFFSET without having it all on one worksheet.
It is not OFFSET, it is Data Validation that won´t allow having it all on one worksheet.
But there is a workaround, if you create another named range (for example, named unique) and type =OFFSET(Sheet1!$B$2, 0, 0, COUNT(IF(Sheet1!$B$2:$B$1000="", "", 1)), 1).
Create a drop down box on another sheet and type =unique in "source:"
To make matter more fun, I need the ranges to be dynamic as the user may be adding new records.
I have updated the post, the named range is now dynamic.
Keels,
I have re-created the above formula but would like to create a range that is larger than the current data so that the unique list picks up all new data. Currently my unique list repeats the last line of data several times because the range name extends beyond it. Can this be done?
I have updated this post, the named range is now dynamic.
This is almost exactly what I have been looking for. The only shortcoming is that I need it to work with spaces (empty cells) in the source list and able to handle a source list that is only one item. I want the person to begin to fill out a column (the source list) filling in names and as they go they can instead pick from a drop down menu so they do not have to type the name (and so the name is always the same). When they type the first name in, it does not appear in the list. Only when they type the second name, then both names appear. Can this be fixed? They are allowed to skip rows filling out the table, so handling blank cells is important too. Thank you.
Peter,
Array formula to remove blanks in blog post example:
=INDEX(List, MATCH(0, IF(MAX((COUNTIF($B$1:B1, $A$2:$A$15)=0)*(($A$2:$A$15<>"")*(COUNTIF($A$2:$A$15, ">"&$A$2:$A$15)+1)))=(IF(($A$2:$A$15<>""), COUNTIF($A$2:$A$15, ">"&$A$2:$A$15)+1, "")), 0, ""), 0)) + CTRL + SHIFT + ENTER
I dont´t understand this:
I want the person to begin to fill out a column (the source list) filling in names and as they go they can instead pick from a drop down menu so they do not have to type the name (and so the name is always the same). When they type the first name in, it does not appear in the list. Only when they type the second name, then both names appear. Can this be fixed?
That revised formula worked perfectly. It solved both the problem with spaces interspersed in the source list and the diminutive situation with only one item in the source list (yielding a one item menu). I can't see any reason someone would not prefer this revised equation over the original. I would update your example above to use this formula instead.
As for my explanation as to what I am doing..... sorry that was clear as mud....
I want a column of data entry cells on a form that allows either free form text entry or a dynamic drop down menu of the items the person already typed into that same column. This way they don't have to "type" the same name twice (can pick it from the menu the second time). It makes data entry faster and increases the likely hood that multiple duplicate entries will be the exact same. To allow text entry at the same time as menu selection, I just turn off the data validation error message.
Over time I may build a dynamic list of names from past times the form was filled out so that this drop down menu does not start out blank each time. But right now this is still helpful to the user (and me).
Thank you very much.... I have yet to figure out how all these complex array formulas work. Right now you are the magician and I am the kid in awe.
Peter,
Maybe you can use these instructions:
Excel Data Validation -- Hide Previously Used Items in Dropdown and modify formulas to only show previously used items in a drop down list.
Thanks Oscar,
That might come in handy some day. In the process of scoping that out I stumbled on a bunch of other potentially useful data validation methods including selecting multiple items from a menu.
"If God didn't invent Excel, I bet that's where he spends most of his time." - Peter V.
This is really good; thanks for posting.
Chris,
thank you!
may i ask the maximum limit on the amount of records you can have in a dropdown list?
thanks.
Juna,
I can´t enter more than 32767 values in a drop down list in excel 2007.
Maybe someone else can shed some light on this, I can´t find anything about this (google).
tnx oscar for this formula
but i have a problem with that.
it has to calculate about 8000 cells and it slows down my pc badly.
any suggestions?
luka,
I have updated this article with a vba function. Download the attached file!
Hi
The dropdown unique listing is really helpful and i appreciate that.
Eddy Stanley,
Thanks!
Hi,
I have a requirement (read problem). I have created a drop down list with following items:
1.Above
2.Below
3.At par
I want if someone choose Above, a formula for escalation of value is executed, if Below a formula for Degradation of value, if At par is used no change in the value.
I am unable to link the chosen field in formula.
Kindly help.
Thanks
DJ,
I am not sure that is possible. What is the formula for escalation of a value?
I would suggest a spin button (form control) and link the control to a cell.
I have a problem if in Column A i have only one value 'DD' (means A1 as List and A2 as DD) then no value are coming in column B using
=INDEX(List, MATCH(0, IF(MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1))=(COUNTIF(List, ">"&List)+1), 0, 1), 0))
Can u plz give me the fix to it. I am also trying but not sure about it.
This is urgent..
Nidhi,
For some reason that I don´t understand, the dynamic named range used in a function returns an error when the List contains a single value.
I am not sure how to resolve this, maybe you can use a - or # character in the first cell and "DD" in the second cell?
Oscar,
Great work and a huge time saver!!! Thank you.
[quote]For some reason that I don´t understand, the dynamic named range used in a function returns an error when the List contains a single value.[/quote]
It has to do with the way Excel evaluates expressions. When you have only one value, Excel reduces the expressions for the "range" inside of Match as a single unique value, rather than a range of values with only one element in it. Since Match expects its second argument to be a range, then it throws the error.
Example:
The way we'd like Excel to evaluate the "Match" expressions would be:
=MATCH(0, {0},0)
Instead, Excel evaluates it as (note the second argument is plainly "0", a number, and not the array {0}:
=MATCH(0, 0,0)
To correct this, one can force Excel to calculate the result of the "if" as an array, as follows (note the "{0}+" part):
=INDEX(List,MATCH(0,{0}+IF(MAX(NOT(COUNTIF($B$1:B1,List))*(COUNTIF(List,">"&List)+1))=(COUNTIF(List,">"&List)+1),0,1),0))
Hope this helps
Mijael,
Thanks for your valuable contribution!
Another, "one-row-code", VBA tip:
Sub MakeUniqueList() Range("A1:A10").AdvancedFilter Action:=xlFilterCopy, _ CopyToRange:=Range("B1"), Unique:=True End Sub!!! Only be aware, that the value from the first line will be taken as the title.
Palo
Thank you so much Oscar. This is really great esp. the explanation of the formulae !
Many thanks for the COUNTIF trick, Oscar. This helps me a lot.
I would change it in a shorter formula, and it works.
=INDEX(List, MATCH((COUNTIF(List, ">"&List)+1), MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1), 0))
If the data contains all numbers, I will use rank(list,list) to replace (COUNTIF(List, ">"&List)+1)
=INDEX(List, MATCH(RANK(List,List), MAX(NOT(COUNTIF($B$1:B1, List))*RANK(List,List), 0))
sorry, I made a mistake.
I would change it in a shorter formula, and it works.
=INDEX(List, MATCH(MAX(NOT(COUNTIF($B$1:B1, List))*(COUNTIF(List, ">"&List)+1)), (COUNTIF(List, ">"&List)+1), 0))
If the data contains all numbers, I will use rank(list,list) to replace (COUNTIF(List, ">"&List)+1)
=INDEX(List, MATCH(MAX(NOT(COUNTIF($B$1:B1, List))*RANK(List,List)), RANK(List,List), 0))
[...] Names -- Excel Named Ranges Excel Magic Trick # 259: Dynamic DV List Based On DV List - YouTube Create a drop down list containing only unique distinct alphabetically sorted text values using exce... I hope these help and good luck with your project. [...]
[...] OFFSET or Table Feature? - YouTube excelisfun -- Excel How To Videos - YouTube Or here.... Create a drop down list containing only unique distinct alphabetically sorted text values using exce... For Question 2, you can concatenate (join) your two cells and use a Conditional Formatting [...]