Please Note: This article is written for users of the following Microsoft Excel versions: 2007, 2010, and 2013. If you are using an earlier version (Excel 2003 or earlier), this tip may not work for you. For a version of this tip written specifically for earlier versions of Excel, click here: Playing with a Full Deck.

Playing with a Full Deck

by Allen Wyatt
(last updated December 5, 2017)

6

Excel is great at generating random numbers, but it is less great at filling a range of cells with random numbers in which no particular number is repeated twice. For instance, you might want to populate 52 cells with the numbers 1 through 52, in random order. (This is very similar to choosing cards from a deck in random order, where a particular card can only be chosen once. Thus the title for this tip.)

There obviously is no built-in Excel function to provide this capability, so you are left to work with macros. Fortunately, such a macro is not terribly difficult to create. The following macro will do the trick nicely:

Sub FillRand()
    Dim nums() As Integer
    Dim maxval As Integer
    Dim nrows As Integer, ncols As Integer
    Dim j As Integer, k As Integer
    Dim Ptr As Integer
    Randomize

    Set s = Selection
    maxval = s.Cells.Count
    nrows = s.Rows.Count
    ncols = s.Columns.Count

    ReDim nums(maxval, 2)

    'Fill the initial array
    For j = 1 To maxval
        nums(j, 1) = j
        nums(j, 2) = Int((Rnd * maxval) + 1)
    Next j

    'Sort the array based on the random numbers
    For j = 1 To maxval - 1
        Ptr = j
        For k = j + 1 To maxval
            If nums(Ptr, 2) > nums(k, 2) Then Ptr = k
        Next k
        If Ptr <> j Then
            k = nums(Ptr, 1)
            nums(Ptr, 1) = nums(j, 1)
            nums(j, 1) = k
            k = nums(Ptr, 2)
            nums(Ptr, 2) = nums(j, 2)
            nums(j, 2) = k
        End If
    Next j

    'Fill in the cells
    Ptr = 0
    For j = 1 To nrows
        For k = 1 To ncols
            Ptr = Ptr + 1
            s.Cells(j, k) = nums(Ptr, 1)
        Next k
    Next j
End Sub

This macro uses a two-dimensional array (nums) to figure out which numbers to use and the order in which they should be used. Near the beginning of the macro the array is filled with a static number (1 through the number of cells) and a random number between 1 and the number of cells. This second number is then used to sort the array. Once the array is stored, it is a simple matter to place the original numbers in the cells.

By the way, the reason a two-dimensional array is used is because the Rnd function that VBA uses to generate random numbers can return duplicate values. Thus, even through the second dimension of the array can have duplicates in it, when the array is finally sorted, the first dimension will not have duplicates.

To use the macro, start by selecting the cells you want to have filled with sequential values in a random order. When you run the macro, that range is filled. For instance, if you select ten cells and then run the macro, then those cells are filled with the numbers 1 through 10, in random order.

ExcelTips is your source for cost-effective Microsoft Excel training. This tip (8269) applies to Microsoft Excel 2007, 2010, and 2013. You can find a version of this tip for the older menu interface of Excel here: Playing with a Full Deck.

Author Bio

Allen Wyatt

With more than 50 non-fiction books and numerous magazine articles to his credit, Allen Wyatt is an internationally recognized author. He  is president of Sharon Parq Associates, a computer and publishing services company. ...

MORE FROM ALLEN

Understanding the VLOOKUP Function

Functions are at the heart of Excel's power in working with data. One of the most misunderstood functions provided by ...

Discover More

Pasting a Hyperlink

When you paste information into a document, you can specify that it be inserted as a hyperlink rather than as normal ...

Discover More

Merging and Printing a Series of Documents

Do you need to merge and print a number of documents in a particular order? Perhaps the best approach is to record a ...

Discover More

Professional Development Guidance! Four world-class developers offer start-to-finish guidance for building powerful, robust, and secure applications with Excel. The authors show how to consistently make the right design decisions and make the most of Excel's powerful features. Check out Professional Excel Development today!

More ExcelTips (ribbon)

Splitting Sentences to Cells

If you have a lot of text in your workbook, at some point you might want to split out sentences into individual cells. ...

Discover More

Counting Words

Do you need to know how many words are in a range of cells? Excel provides no intrinsic way to count the words, but you ...

Discover More

Requiring Input

If you distribute a workbook that is used by others for data entry, you may want a way to make sure they fill in certain ...

Discover More
Subscribe

FREE SERVICE: Get tips like this every week in ExcelTips, a free productivity newsletter. Enter your address and click "Subscribe."

View most recent newsletter.

Comments

If you would like to add an image to your comment (not an avatar, but an image to help in making the point of your comment), include the characters [{fig}] in your comment text. You’ll be prompted to upload your image when you submit the comment. Maximum image size is 6Mpixels. Images larger than 600px wide or 1000px tall will be reduced. Up to three images may be included in a comment. All images are subject to review. Commenting privileges may be curtailed if inappropriate images are posted.

What is three more than 8?

2017-12-10 20:21:00

Darren E

Thumbs Up, Willy!!


2017-12-08 11:12:01

Willy Vanhaelen

Indeed Rick's solution is a gem as usual. He claims his macro will be much faster than Alan's but didn't test it. I did and it is about 50 times faster !!! But while testing, I discovered his macro has a minor limitation: it has a limit of 65537 cells :-)
Further investigation revealed that TRANSPOSE is responsible for that. So I tried to produce the Num array only with ROW and it worked though the array is now two dimensional. I further took UBound(Nums) out of the loop because it doesn't change during the execution of the macro anyway. This makes the code in the loop a little bit simpler. Here is the result:

Sub FillRand()
Dim X As Long, RandIndex As Long, Nums As Variant, Cell As Range
Randomize
Nums = Evaluate("ROW(1:" & Selection.Count & ")")
X = UBound(Nums)
For Each Cell In Selection
RandIndex = Int(X * Rnd + 1)
Cell.Value = Nums(RandIndex, 1)
Nums(RandIndex, 1) = Nums(X, 1)
X = X - 1
Next Cell
End Sub

I did a test in Excel 2007 for a whole column and it took only 16 seconds to process the more than a million cells.


2017-12-05 23:16:20

Darren E

That is a really clever algorithm Rick Rothstein!


2016-01-09 10:56:53

Rick Rothstein

I don't know if Thomas or Bryan will still be following replies to this blog article or not, but I believe the following macro (which I just posted to Allen Wyatt's other blog article referenced in the "Please Note" box at the top of this blog article) will be faster (untested claim) than Allen Wyatt's code no matter what sorting method was used because my code does not use any sorting whatsoever.

Sub FillRand()
Dim X As Long, RandIndex As Long, Nums As Variant, Cell As Range
Randomize
Nums = Evaluate("TRANSPOSE(ROW(1:" & Selection.Count & "))")
For Each Cell In Selection
RandIndex = Int((UBound(Nums) - X) * Rnd + 1)
Cell.Value = Nums(RandIndex)
Nums(RandIndex) = Nums(UBound(Nums) - X)
X = X + 1
Next
End Sub

Note: This macro will work in XL2003 or later for sure... it may work in earlier versions as well, but XL2003 is the earliest version I own, so I cannot be sure about earlier versions.


2013-09-30 10:01:31

Bryan

Thomas, Allen's solution is actually relatively simple and it's the exact same principal as yours; the difference is the internal Excel sorting method is faster than Allen's. This makes me sad, because his method is more "proper"; I'm guessing, however, that with a more advanced sorting algorithm you could get the times to approach each other.

CPearson has a method that is even faster than using the worksheet to sort (http://www.cpearson.com/excel/SortingArrays.aspx) I tested all 4 methods and here are the results I got with 7,700 values to sort:

Allen Sort: 30.4057
Wrksht Sort: 0.3405
CPrson Sort: 0.1668


With something more reasonable (52, since we are talking cards), the time difference is negligible:

Allen Sort: 0.0015
Wrksht Sort: 0.0738
CPrson Sort: 0.0005

This time the worksheet sorting solution is actually the slowest!


2013-09-28 14:52:43

Thomas Papavasiliou

The proposed method works OK but I think that it is rather complicated.

A simpler and much faster way is to insert two new columns in A and B and fill the first new column A, with a sequence of numbers from 1 to the number of cells in the selection, place next to it, that is the second inserted column B the formula =rand() and fill it down.
Then sort the two new columns having B as key and cutting the sorted A column, to slices equal to the number of rows of the selection and moving them to the selection.

A trial with some 550 rows and 14 columns, run on my PC approximately seven times faster.

If anybody is interested in this version I will be pleased to provide it


This Site

Got a version of Excel that uses the ribbon interface (Excel 2007 or later)? This site is for you! If you use an earlier version of Excel, visit our ExcelTips site focusing on the menu interface.

Newest Tips
Subscribe

FREE SERVICE: Get tips like this every week in ExcelTips, a free productivity newsletter. Enter your address and click "Subscribe."

(Your e-mail address is not shared with anyone, ever.)

View the most recent newsletter.