Hi. Here's another way. Note that in your example, we assume the size of
the subset from the given array of values. (we don't supply the '6).
We do have to give the size of the set though.
Sub TestYourData()
'//Easy Test (1)
Debug.Print RankKSubset(9, 1, 2, 3, 4, 5, 6)
'// Other easy test...
Debug.Print RankKSubset(9, 4, 5, 6, 7, 8, 9)
Debug.Print [Combin(9,6)]
Debug.Print RankKSubset(50, 1, 7, 23, 35, 47, 49)
Debug.Print RankKSubset(20, 1, 2, 3, 4, 5, 19)
Debug.Print RankKSubset(20, 1, 2, 3, 4, 5, 14)
End Sub
Function RankKSubset(Size, ParamArray v())
'//= = = = = = = = = = = = = = = = = =
'// By: Dana DeLouis
'//= = = = = = = = = = = = = = = = = =
Dim j As Long
Dim d As Double
Dim n As Double
Dim m As Double
Dim T As Double
With WorksheetFunction
m = Size
n = UBound(v) + 1
d = v(0)
T = T + .Combin(m, n) - .Combin(m - d + 1, n)
For j = 1 To UBound(v) - 1
m = m - d
n = n - 1
d = v(j) - v(j - 1)
T = T + .Combin(m, n) - .Combin(m - d + 1, n)
Next j
T = T + v(j) - v(j - 1)
End With
RankKSubset = T
End Function
To convert a number to a subset, we need to supply both the size of the set,
and the size of the subset.
So, in our example of 50 & 6, we note that if our number falls within
=COMBIN(49,5) = 1906884
then our first digit is 1.
If n is greater than this, then we add =COMBIN(48,5) = 1712304
If n falls within this new number, then the first number is 2...etc
We have to do these short loops because there is no analytical way to
directly solve the binomial sum (afaik)
As a side note, when your size gets too large, it can sometimes be more
efficient to call a NextPermutation routine
I've done this before, but I can't find it at the moment.
The reason for this is that if you had a size 1000, and a subset size of 14,
then this exceeds Excel's extended capabilities.
For example, if you had this size 14 subset out of 1,000:
{2, 39, 140, 230, 262, 341, 443, 558, 612, 661, 674, 705, 804, 839}
then it would be the
202,646,961,038,399,155,876,623,226,251
'th item in the list.
This slightly exceeds Excel's extended capabilities.
Hence, it is usually faster to work with the smaller array.
--
Dana DeLouis
"PST" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
thank you for your reply
I think that you are right
"I believe the Op is asking for the "Rank"
I will want the way simplest to have the Rank
ex: combin(20,6)
(1,2,3,4,5,19) rank is 14
(1,2,3 4,5,14) rank is 9
how to have it and use the functions RankKSubset UnrankKSubs
and they are not in Excel
>>>>>
I believe the Op is asking for the "Rank"
>
> n = RankKSubset[{1, 7, 23, 35, 47, 49}, s] + 1
>
> 926,277
>
> (ie it's the 926,277 item in the list)
>
> and then wanting to "UnRank" it.
>
> UnrankKSubset[n, 6, s]
>
> {1, 7, 23, 35, 47, 50}
>
> Again, I may be wrong.
>
> --
> Dana DeLouis
>
> <snip>Joel a écrit :
> Ther was no error in my code. I wasn't sure if the PST wanted 2 to the N
> combinitions or PST was looking for N! (factorial) permutations. Sinced
> you asked for permutations here is the modified code. It looks very
> similar except I do a check to make sure the number isn't used more than
> once.
>
> P.S. I was expecting somebody to respond with the question why were the
> numbers appearing twice. A couple of weeks ago somebody posted a
> requested for permutations, so I knew exactly how to make the changes
> before the question was asked.
>
>
> Const Forward As Integer = 0
> Const Reverse As Integer = 1
> Public MyNumbers() As Variant
> Public SearchArray() As Variant
> Public combinationArray() As Variant
> Public ArraySize As Integer
> Public LowerLimit As Double
> Public UpperLimit As Double
> Sub test()
>
> Dim index As Long
> Dim ComboNo As Double
> MyNumbers = Array(1, 6, 7, 23, 35, 47, 49, 50)
> SearchArray = Array(50, 6, 1, 7, 23, 35, 47, 49)
> ArraySize = UBound(MyNumbers)
> ReDim combinationArray(ArraySize)
> index = 0
> level = 0
> StartIndex = CombinationToIndex(Forward, level, index)
> LowerLimit = StartIndex
> UpperLimit = StartIndex + 99#
> index = 0
> level = 0
> StartIndex = CombinationToIndex(Reverse, level, index)
> End Sub
>
> Function CombinationToIndex(Mode, level, ByRef index As Long)
>
> For i = 0 To ArraySize
> found = False
> For n = 0 To (level - 1)
> If combinationArray(n) = i Then
> found = True
> Exit For
> End If
> Next n
> If found = False Then
> combinationArray(level) = i
> If level = ArraySize Then
> If Mode = Forward Then
> 'check if search value was found
> found = True
> For j = 0 To ArraySize
> If SearchArray(j) <> _
> MyNumbers(combinationArray(j)) Then
> found = False
> Exit For
> End If
> Next j
> If found = True Then
> CombinationToIndex = index
> Exit For
> Else
> CombinationToIndex = -1
> End If
> Else
> If index >= LowerLimit Then
> For k = 0 To ArraySize
> If k = 0 Then
> PrintString = _
> CStr(MyNumbers(combinationArray(k)))
> Else
> PrintString = PrintString & "," & _
> CStr(MyNumbers(combinationArray(k)))
> End If
> Next k
> MsgBox (PrintString)
> If index = UpperLimit Then
> CombinationToIndex = 0
> Exit For
> Else
> CombinationToIndex = -1
> End If
> Else
> CombinationToIndex = -1
> End If
> End If
> index = index + 1
> Else
> CombinationToIndex = _
> CombinationToIndex(Mode, level + 1, index)
> End If
> If CombinationToIndex <> -1 Then
> Exit For
> End If
> End If
> Next i
>
> End Function
>
>
> "Dana DeLouis" wrote:
>
>> Hi. Here are your first 6 outputs:
>>
>>> 50,6,1,7,23,35,47,49
>>> 50,6,1,7,23,35,47,50
>>> 50,6,1,7,23,35,49,1
>>> 50,6,1,7,23,35,49,6
>>> 50,6,1,7,23,35,49,7
>>> 50,6,1,7,23,35,49,23
>> I may be wrong, but I think there is a logic error in the code.
>> I read the op's question as being that from a set of s=50, and Subsets of
>> size 6,
>> find the next Subset in Lexicographical order.
>> (Using another program, the next Subset appears correct:
>>
>> NextKSubset[s, {1, 7, 23, 35, 47, 49}]
>> {1, 7, 23, 35, 47, 50}
>>
>> But your third one is a little off.
>>
>> NextKSubset[s, %]
>> {1, 7, 23, 35, 48, 49}
>>
>> Also note that your 6th output has two "23's", which can not be part of a
>> Subset in this context.
>>
>> I believe the Op is asking for the "Rank"
>>
>> n = RankKSubset[{1, 7, 23, 35, 47, 49}, s] + 1
>>
>> 926,277
>>
>> (ie it's the 926,277 item in the list)
>>
>> and then wanting to "UnRank" it.
>>
>> UnrankKSubset[n, 6, s]
>>
>> {1, 7, 23, 35, 47, 50}
>>
>> Again, I may be wrong.
>>
>> --
>> Dana DeLouis
>>
>> <snip>
>>
>>