MS Office Forum / Excel / Programming / December 2006
seeking John Coleman
|
|
Thread rating:  |
chipl3ader@gmail.com - 02 Dec 2006 05:28 GMT Hi John,
You helped me solve a problem recently with combining values in Excel. I was wondering if you would mind helping me out again. I have tried to do it myself but I just can't get it to work the way I would l like.
What I'm hoping to accomplish is similar to before but it would be combining two of the first dialog boxes with 3 of the second dialog box in all permutations. So, as before given my values as such:
A vs B C vs D E vs F G vs H I vs J
I would like to see an output like so:
A C F H J A E D H J A G D F J A I D F H
C E B H J C G B F J C I B F H
E G B D J E I B D H
G I B D F
If you wouldn't mind helping out a VBA challenged chump again, it would be greatly appreciated.
Regards, jugrnt
John Coleman - 02 Dec 2006 15:18 GMT Hi Jugrnt,
When I saw the message title I was afraid that the FBI had finally caught up with me.
Try this:
+++++++++++++++++++++++++++++++++++++++++++++++++++++
Sub CombineValues2() Dim LHS As Variant Dim RHS As Variant Dim Vals As Variant Dim n As Long Dim i As Long, j As Long, k As Long, l As Long, m As Long Dim currentRow As Long
Vals = InputBox("Enter list of opponents, separated by commas") Vals = Replace(Vals, "vs", ",", , , vbTextCompare) Vals = Replace(Vals, " ", "") Vals = Split(Vals, ",") n = UBound(Vals) If n Mod 2 = 0 Or n < 9 Then MsgBox "Invalid Input" Exit Sub End If ReDim LHS(0 To (n - 1) / 2) ReDim RHS(0 To (n - 1) / 2) For i = 0 To n If i Mod 2 = 0 Then LHS(j) = Vals(i) j = j + 1 Else RHS(k) = Vals(i) k = k + 1 End If Next i n = UBound(LHS) Range("A:A").ClearContents For i = 0 To n - 1 For j = i + 1 To n For k = 0 To n - 2 For l = k + 1 To n - 1 For m = l + 1 To n If k <> i And l <> i And m <> i And _ k <> j And l <> j And m <> j Then Range("A1").Offset(currentRow).Value = _ LHS(i) & " " & LHS(j) & " " & _ RHS(k) & " " & RHS(l) & " " & RHS(m) currentRow = currentRow + 1 End If Next m Next l Next k Next j currentRow = currentRow + 1 Next i End Sub
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
I changed how the input worked. In my original version I was a bit lazy and used 2 input boxes to load the 2 arrays. Now I have a single input box that expects input in the form
A vs B, C vs D, E vs F, G vs H, I vs J
which strikes me as closer to what you are looking for (although it would be easy enough to go back to the original format). The commas are needed as pair separators but the rest is pretty forgiving, ie, A vs B can even be written as AVSB. By the way, my original code contained a subtle bug - it doesn't work if you put more than 1 space between input elements. Nothing really wrong with that - I could call it a "feature" - but it made my use of the Trim function pointless. This version simply removes any spaces so that A vs B, Avs B, A vsB, etc. all have the same result. I am assuming that 1) What plays the role of A, B etc is not a string containing "vs" and 2) What plays the role of A, B doesn't contain any spaces This seems to be consistent with your examples but might be unfortunate if you want to have things like "The Cavs vs The Pistons" - but that can be changed at the cost of a bit more care in the parsing. Let me know if this is a problem.
HTH
-John Coleman
> Hi John, > [quoted text clipped - 33 lines] > Regards, > jugrnt chipl3ader@gmail.com - 02 Dec 2006 19:22 GMT Hi John,
Sorry if the message title caused you to gulp!
Once again you've knocked it out of the park! It's a thing of beauty and was exactly what I was looking for. And, your hunch about what this may be used for, Cavs vs Pistons, is pretty bang on except that I'm interested in NHL games. I don't foresee the "vs" being a problem with any NHL team names as I always shorthand the city names (mtl tor det chi etc). Having said that, I had changed your previous dialog boxes to "Enter Favorites, seperated by spaces" and "Enter Dogs..." which worked well for me. If you are curious, Dogs beat the spread at about a 65% clip in the NHL (has been pretty consistent to that number the past 3 or 4 seasons) so I'm gonna run this a little while and see how it works.
Again, thank you very much for your help and all the best to you!
Regards, jugrnt
> Hi Jugrnt, > [quoted text clipped - 121 lines] > > Regards, > > jugrnt John Coleman - 02 Dec 2006 22:13 GMT Hi jugrnt,
I got interested in the problem of writing a single sub that can handle your orginal request from last month, the one from today and any sufficiently similar one in the future. It takes as input a favorite list like A,B,E,G,I,K,M a corresponding dog list like B,D,F,H,J,L,N (note that I am back to 2 lists rather than a list of pairs but that I am now using commas as delimiters - you can easily modify the code to go back to spaces, but I personally don't trust spaces as delimiters because of the hassle of worrying about extra spaces). Furthermore - as input you also now supply the number of favorites as well as the number of dogs per row, so that if you want 3 favorites and 3 dogs from the above the output will begin
A C E H J L A C E H J N A C E H L N A C E J L N A C G F J L A C G F J N A C G F L N A C G J L N
and so so for 144 rows (including spaces inserted when the A in the first column turns into a B, etc. Your original request was 1 favorite and 3 dogs and today it was for 2 and 3
I dont know if you need this generality - but it struck me as being an interesting problem:
*************************************************************************
Sub CombineValues3() Dim LHS As Variant Dim RHS As Variant Dim LTuple As Variant Dim RTuple As Variant Dim n As Long Dim i As Long, j As Long, k As Long Dim currentRow As Long Dim currentFav As String Dim rowString As String Dim numFavs As Long, numDogs As Long
LHS = InputBox("Enter Favorites, separated by commas") LHS = Split(LHS, ",") RHS = InputBox("Enter Dogs, separated by commas") RHS = Split(RHS, ",") n = UBound(LHS) If n <> UBound(RHS) Then MsgBox "Invalid Input" & vbCrLf & _ "Number of Favorites must = number of Dogs" Exit Sub End If For i = 0 To n LHS(i) = Trim(LHS(i)) RHS(i) = Trim(RHS(i)) Next i numFavs = InputBox("Enter number of Favorites per row") numDogs = InputBox("Enter number of Dogs per row") If numFavs + numDogs > n + 1 Then MsgBox "Not enough teams for that type of output" Exit Sub End If Application.ScreenUpdating = False Range("A:A").ClearContents ReDim LTuple(0 To numFavs - 1) ReDim RTuple(0 To numDogs - 1) For i = 0 To numFavs - 1 LTuple(i) = i Next i currentFav = LTuple(0) For i = 1 To Application.WorksheetFunction.Combin(n + 1, numFavs) For j = 0 To numDogs - 1 RTuple(j) = j Next j For j = 1 To Application.WorksheetFunction.Combin(n + 1, numDogs) If Disjoint(LTuple, RTuple, n) Then If LTuple(0) <> currentFav Then currentRow = currentRow + 1 currentFav = LTuple(0) End If rowString = "" For k = 0 To numFavs - 1 rowString = rowString & LHS(LTuple(k)) & " " Next k For k = 0 To numDogs - 1 rowString = rowString & RHS(RTuple(k)) & " " Next k rowString = RTrim(rowString) Range("A1").Offset(currentRow).Value = rowString currentRow = currentRow + 1 End If NextTuple RTuple, numDogs, n Next j NextTuple LTuple, numFavs, n Next i Application.ScreenUpdating = True End Sub
Sub NextTuple(T As Variant, k As Long, n As Long) 'This sub takes a 0-based variant array representing 'a k-element subset of {0,1,...,n} and changes 'it to the next one in lex order 'it has no effect if the tuple has no successor
On Error GoTo no_successor Dim i As Long, j As Long, M As Long M = n i = k - 1 Do While T(i) = M i = i - 1 M = M - 1 Loop T(i) = T(i) + 1 For j = i + 1 To k - 1 T(j) = T(j - 1) + 1 Next j no_successor: End Sub
Function Disjoint(S As Variant, T As Variant, n As Long) As Boolean 'This function takes 2 arrays representing 'subsets of {0,1,...,n} and returns True 'if they are disjoint and False otherwise Dim A() As Long Dim i As Long
ReDim A(0 To n) For i = LBound(S) To UBound(S) A(S(i)) = 1 Next i For i = LBound(T) To UBound(T) If A(T(i)) = 1 Then Disjoint = False Exit Function End If Next i Disjoint = True End Function
******************************************************************
HTH
-John Coleman
> Hi John, > [quoted text clipped - 142 lines] > > > Regards, > > > jugrnt chipl3ader@gmail.com - 02 Dec 2006 22:56 GMT John,
You've really outdone yourself this time! I just tried out your new code and I am stunned. That is even better than I could have imagined. It's very powerful, efficient and flexible for days where there are few or many games on the schedule. And being able to specify how many faves or dogs per row is perfect! You've saved me so much time and effort, I cannot possibly thank you enough. I can only hope that you enjoyed the problem and coding a solution. I'm totally floored!! I will try to keep you posted as to how my little experiement goes.
Best Regards, jugrnt
> Hi jugrnt, > [quoted text clipped - 290 lines] > > > > Regards, > > > > jugrnt John Coleman - 03 Dec 2006 13:23 GMT >(snipped for berivity) jugrnt,
I'm glad that you liked it. A few final remarks
1) Input boxes can easily become tedious. It would be easy to modify the sub so that it takes a list of favorites in column A and a list of dogs in column B and then puts the output in column C 2) Upon further thought, my algorithm is not very efficient. Most of the candidate rows that I generate are promptly discarded by the line "If Disjoint(LTuple,RTuple)..." My hunch is that while my current algorithm would just take seconds for up to a dozen teams or so it might take minutes by the time you get to say 20 teams or so. I haven't experimented with it, so I don't know exactly where the threshhold of inefficiniency is, but it is there somewhere. If it is a problem, let me know - I have already mentally outlined a much more efficient approach, but it would involve more or less starting from scratch. 3) If you want to post further on this thread - just reply to this rather than starting a new thread. Given the sheer volume of this newsgroup and given that this is more of a hobby of mine than something I do professionally, I could easily miss a new thread, even if my name is in the topic. I don't want to make the FBI's job too easy.
I hope your experiments prove productive.
-John
|
|
|