VBA to sort/distribute evenly

liampog

Active Member
Joined
Aug 3, 2010
Messages
308
Office Version
  1. 365
  2. 2016
Platform
  1. Windows
Hi

I have a list of data that will include numbers 1,2,3,4. First, I have some code that sorts into ascending order, but then I'd like some more code that then distributes the list as follows. Original in Column A and the desired order in Column C. In this example, there are 6x 1, 8x 2, 5x 3, 6x 4:

Note cell C23 is 4 because the 3's have run out. Also note cells C24 and C25 because there are 2 more 2's left over.


ABC
111
212
313
414
511
612
723
824
921
1022
1123
1224
1321
1422
1533
1634
1731
1832
1933
2044
2141
2242
2344
2442
2542

<tbody>
</tbody>
 

Excel Facts

Does the VLOOKUP table have to be sorted?
No! when you are using an exact match, the VLOOKUP table can be in any order. Best-selling items at the top is actually the best.
Try this:-
NB:- The last 4 rows are not Quite in the same order as your Data, Does that Matter??
Code:
[COLOR="Navy"]Sub[/COLOR] MG21Dec14
[COLOR="Navy"]Dim[/COLOR] Rng [COLOR="Navy"]As[/COLOR] Range, Dn [COLOR="Navy"]As[/COLOR] Range, n [COLOR="Navy"]As[/COLOR] [COLOR="Navy"]Long[/COLOR]
[COLOR="Navy"]Set[/COLOR] Rng = Range(Range("A1"), Range("A" & Rows.Count).End(xlUp))
[COLOR="Navy"]With[/COLOR] CreateObject("scripting.dictionary")
.CompareMode = vbTextCompare
[COLOR="Navy"]For[/COLOR] [COLOR="Navy"]Each[/COLOR] Dn [COLOR="Navy"]In[/COLOR] Rng
    [COLOR="Navy"]If[/COLOR] Not .Exists(Dn.Value) [COLOR="Navy"]Then[/COLOR]
        .Add Dn.Value, 1
    [COLOR="Navy"]Else[/COLOR]
        .Item(Dn.Value) = .Item(Dn.Value) + 1
    [COLOR="Navy"]End[/COLOR] If
[COLOR="Navy"]Next[/COLOR]
oMax = Application.Max(.keys())
[COLOR="Navy"]For[/COLOR] [COLOR="Navy"]Each[/COLOR] Dn [COLOR="Navy"]In[/COLOR] Rng
    c = c + 1
    c = IIf(c = oMax + 1, 1, c)
    [COLOR="Navy"]If[/COLOR] .Item(c) = 0 [COLOR="Navy"]Then[/COLOR]
        [COLOR="Navy"]For[/COLOR] [COLOR="Navy"]Each[/COLOR] k [COLOR="Navy"]In[/COLOR] .keys
            [COLOR="Navy"]If[/COLOR] Not .Item(k) = 0 [COLOR="Navy"]Then[/COLOR]
                Dn.Offset(, 2).Value = k
                .Item(k) = .Item(k) - 1
                [COLOR="Navy"]Exit[/COLOR] For
            [COLOR="Navy"]End[/COLOR] If
        [COLOR="Navy"]Next[/COLOR] k
    [COLOR="Navy"]Else[/COLOR]
        Dn.Offset(, 2).Value = c
        .Item(c) = .Item(c) - 1
    [COLOR="Navy"]End[/COLOR] If
[COLOR="Navy"]Next[/COLOR] Dn
[COLOR="Navy"]End[/COLOR] [COLOR="Navy"]With[/COLOR]
[COLOR="Navy"]End[/COLOR] [COLOR="Navy"]Sub[/COLOR]
Regards Mick
 
Upvote 0
Hi Mick

This works perfectly but I don't think I've explained myself properly :)

This is more a sorting thing rather than taking a set of data and changing it into something else.

If we say that Column B has unique staff names with each staff member assigned a category number in Column A.

I'd like to sort the numbers (and corresponding names) into the order in Column C.

Does that make better sense?
 
Upvote 0
Sure...

So the data would start as below.....

A (name)B (category)
1Staff 11
2Staff 21
3Staff 31
4Staff 41
5Staff 52
6Staff 62
7Staff 72
8Staff 82
9Staff 92
10Staff 102
11Staff 113
12Staff 123
13Staff 133
14Staff 143
15Staff 153
16Staff 163
17Staff 173
18Staff 184
19Staff 194
20Staff 204

<tbody>
</tbody>

and end up as below after sorting it somehow?

Maybe there needs to be a helper column in C that assigns 1 to 20?



A (name)B (category)
1Staff 11
2Staff 52
3Staff 113
4Staff 184
5Staff 21
6Staff 62
7Staff 123
8Staff 194
9Staff 31
10Staff 72
11Staff 133
12Staff 204
13Staff 41
14Staff 82
15Staff 143
16Staff 92
17Staff 153
18Staff 102
19Staff 163
20Staff 173

<tbody>
</tbody>
 
Upvote 0
I'm not sure if this meets your requirements.
You will see the bottom 4 rows are not as per your results, but are they acceptable ???
Staff 11
Staff 52
Staff 113
Staff 184
Staff 21
Staff 62
Staff 123
Staff 194
Staff 31
Staff 72
Staff 133
Staff 204
Staff 41
Staff 82
Staff 143
Staff 92
Staff 102
Staff 153
Staff 163
Staff 173
<colgroup><col width="102" style="width: 77pt; mso-width-source: userset; mso-width-alt: 3640;"> <col width="113" style="width: 85pt; mso-width-source: userset; mso-width-alt: 4010;"> <tbody> </tbody>
 
Upvote 0
Yes they are acceptable because there are no other 1s and 2s categories.
 
Upvote 0
Try this:-
NB:- This code will overwrite the data in "column "A & B".
Code:
[COLOR="Navy"]Sub[/COLOR] MG22Dec03
[COLOR="Navy"]Dim[/COLOR] Rng [COLOR="Navy"]As[/COLOR] Range, Dn [COLOR="Navy"]As[/COLOR] Range, n [COLOR="Navy"]As[/COLOR] [COLOR="Navy"]Long,[/COLOR] oMax [COLOR="Navy"]As[/COLOR] [COLOR="Navy"]Long,[/COLOR] c [COLOR="Navy"]As[/COLOR] [COLOR="Navy"]Long[/COLOR]
[COLOR="Navy"]Dim[/COLOR] Q [COLOR="Navy"]As[/COLOR] Variant, K [COLOR="Navy"]As[/COLOR] Variant
[COLOR="Navy"]Set[/COLOR] Rng = Range(Range("B2"), Range("B" & Rows.Count).End(xlUp))
ReDim ray(1 To Rng.Count, 1 To 2)
[COLOR="Navy"]With[/COLOR] CreateObject("scripting.dictionary")
.CompareMode = vbTextCompare
[COLOR="Navy"]For[/COLOR] [COLOR="Navy"]Each[/COLOR] Dn [COLOR="Navy"]In[/COLOR] Rng
    [COLOR="Navy"]If[/COLOR] Not .Exists(Dn.Value) [COLOR="Navy"]Then[/COLOR]
        .Add Dn.Value, Array(Dn, 1)
    [COLOR="Navy"]Else[/COLOR]
       Q = .Item(Dn.Value)
        Q(1) = Q(1) + 1
           [COLOR="Navy"]Set[/COLOR] Q(0) = Union(Q(0), Dn)
        .Item(Dn.Value) = Q
    [COLOR="Navy"]End[/COLOR] If
[COLOR="Navy"]Next[/COLOR]
oMax = Application.Max(.keys())
[COLOR="Navy"]For[/COLOR] [COLOR="Navy"]Each[/COLOR] Dn [COLOR="Navy"]In[/COLOR] Rng
    c = c + 1
    c = IIf(c = oMax + 1, 1, c)
    [COLOR="Navy"]If[/COLOR] .Item(c)(1) = 0 [COLOR="Navy"]Then[/COLOR]
      [COLOR="Navy"]For[/COLOR] [COLOR="Navy"]Each[/COLOR] K [COLOR="Navy"]In[/COLOR] .keys
            [COLOR="Navy"]If[/COLOR] Not .Item(K)(1) = 0 [COLOR="Navy"]Then[/COLOR]
               ray(Dn.Row - 1, 2) = K
                Q = .Item(K)
                    Q(1) = Q(1) - 1
                .Item(K) = Q
                [COLOR="Navy"]Exit[/COLOR] For
            [COLOR="Navy"]End[/COLOR] If
        [COLOR="Navy"]Next[/COLOR] K
     [COLOR="Navy"]Else[/COLOR]
        ray(Dn.Row - 1, 2) = c
         Q = .Item(c)
            Q(1) = Q(1) - 1
         .Item(c) = Q
     [COLOR="Navy"]End[/COLOR] If
[COLOR="Navy"]Next[/COLOR] Dn
[COLOR="Navy"]For[/COLOR] n = 1 To Rng.Count
    Q = .Item(ray(n, 2))
        Q(1) = Q(1) + 1
        ray(n, 1) = Q(0)(Q(1)).Offset(, -1).Value
    .Item(ray(n, 2)) = Q
[COLOR="Navy"]Next[/COLOR] n
[COLOR="Navy"]End[/COLOR] With
Range("A2").Resize(Rng.Count, 2) = ray
[COLOR="Navy"]End[/COLOR] [COLOR="Navy"]Sub[/COLOR]
Regards Mick
 
Upvote 0

Forum statistics

Threads
1,214,641
Messages
6,120,684
Members
448,977
Latest member
dbonilla0331

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top