Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
DiscussionsAccessExcelInfoPathOutlookPowerPointPublisherWord
DirectoryUser Groups
Related Topics
Outlook ExpressInternet ExplorerWindowsMS Server ProductsMore Topics ...

MS Office Forum / Excel / Programming / December 2006

Tip: Looking for answers? Try searching our database.

seeking John Coleman

Thread view: 
Enable EMail Alerts  Start New Thread
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
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.