Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Find all possible combinations from lists in an excel spreadsheet

Posted on 2008-10-12
15
1,807 Views
Last Modified: 2012-05-05
I have a spreadsheet that has value that look like this:

Row 1, 5 columns::  bbContag      bbED      bbENN_MN      bbLPI      bbLSI

I need to create a list from these numbers that always contain the value from column1 and then all possible combination of the values from the remaining columns' values, to produce an output like this:

bbContag+bbED+bbENN_MN+bbLPI+bbLSI
bbContag+bbED+bbENN_MN+bbLPI
bbContag+bbED+bbENN_MN
bbContag+bbED
bbContag+bbENN_MN+bbLPI+bbLSI
bbContag+bbENN_MN+bbLPI
bbContag+bbENN_MN
bbContag+bbLPI+bbLSI
bbContag+bbLPI
bbContag+bbLSI
etc, obviously this is not finished.

The output can remain in excel or output to a text file.

The maximum amount of columns with values will be 9, with a minimum of 2. I am looking for a script or macro to do this. Please be advise I currently do not have the wherewithal to do this myself, and would appreciated annotated code so I can begin to learn whats going on. I have attached a spreadsheet that is a sample of what I would like to use a script / macro on.

Thanks,
JE

If I knew what I was doing I might be able to use some of these suggestions, but I don't and that's why I am calling on the good graces of the EE experts:
http://www.ozgrid.com/forum/showthread.php?t=40004
http://www.excelforum.com/excel-programming/632749-list-all-the-combinations-of-a-group-of-cells-containing-letters-but-not-numbers.html

 
je-combo.xls
0
Comment
Question by:justearth
  • 8
  • 4
  • 3
15 Comments
 
LVL 81

Expert Comment

by:byundt
ID: 22700240
One way of looking at this problem is that of counting in binary from 1 to x, where x = 2^n - 1 and n=number of words (not counting the first one). When a bit is "1", then the word is added to the string. When the bit is "0", then the word is not added to the string. For five words in A1:E1, the counting formula to build the string would be:
=$A$1 & IF(MOD(ROW(),2)>=1,"+" & B$1,"")& IF(MOD(ROW(),4)>=2,"+" & C$1,"")& IF(MOD(ROW(),8)>=4,"+" & D$1,"")& IF(MOD(ROW(),16)>=8,"+" & E$1,"")

If you copy this formula down, it will build the requested string. I trust you can generalize the pattern for different numbers of words.

Brad
0
 

Author Comment

by:justearth
ID: 22700256
Brad,
Thanks. So what do I change if I have more than 5 columns?
 Also this includes the value from column A plus itself (i.e. bbContag + bbContag) is there way to make it not do that? It didn't quite work please review the output below (repeats, etc):
bbContag+bbED
bbContag+bbContag
bbContag+bbED+bbContag
bbContag+bbED
bbContag+bbED+bbED
bbContag+bbContag+bbED
bbContag+bbED+bbContag+bbED
bbContag+bbLSI
bbContag+bbED+bbLSI
bbContag+bbContag+bbLSI
bbContag+bbED+bbContag+bbLSI
bbContag+bbED+bbLSI
bbContag+bbED+bbED+bbLSI
bbContag+bbContag+bbED+bbLSI
bbContag+bbED+bbContag+bbED+bbLSI
bbContag


Thanks again,
Cheers,
JE
0
 
LVL 29

Assisted Solution

by:pepr
pepr earned 100 total points
ID: 22700518
For Python, have a look at the standard module itertools and the generator called itertools.permutations() http://docs.python.org/library/itertools.html?highlight=permutations#itertools.permutations

Having the row values in the list, you can get the permutations with all the elements from the row using the code like this:

import itertools

row = ['bbContag', 'bbED', 'bbENN_MN', 'bbLPI', 'bbLSI']

for t in itertools.permutations(row):
    print '+'.join(t)  # join the strings using the '+' or process somehow else

When you also want permutations of smaller lengths, just use the second argument itertools.permutations(row, n) and loop for 1 to the number of elements in the row. See the snippet below. See the attached result.txt with the produced results.
import itertools
 
row = ['bbContag', 'bbED', 'bbENN_MN', 'bbLPI', 'bbLSI'] 
 
# If you want to do also permutations from using not all 
# values in the list, then you can add the second argument
# of the itertools.permutations(row, n) and loop for n
# from 1 to n inclusively.
 
for n in range(1, len(row)+1):
    print '\nPermutations of the length', n
    print '-' * 50
    for t in itertools.permutations(row, n):
        print '+'.join(t)

Open in new window

result.txt
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
LVL 29

Expert Comment

by:pepr
ID: 22700539
The above does not solve the problem of how to get the rows out of the Excel document. The easy approach (if acceptable) could be to export the rows into csv format and then read the csv file using Python's standard module csv.

Sorry for the attached result.txt above. It contains also one more section at the beginning that contains the permutations made of all elements (i.e. from the simpler example typed in front of the snippet). The snippet results start with...

Permutations of the length 1
--------------------------------------------------
bbContag
bbED
bbENN_MN
bbLPI
bbLSI

Permutations of the length 2
--------------------------------------------------
bbContag+bbED
bbContag+bbENN_MN
bbContag+bbLPI
bbContag+bbLSI
bbED+bbContag
bbED+bbENN_MN
bbED+bbLPI
bbED+bbLSI
bbENN_MN+bbContag
bbENN_MN+bbED
bbENN_MN+bbLPI
bbENN_MN+bbLSI
bbLPI+bbContag
bbLPI+bbED
bbLPI+bbENN_MN
bbLPI+bbLSI
bbLSI+bbContag
bbLSI+bbED
bbLSI+bbENN_MN
bbLSI+bbLPI

Permutations of the length 3
--------------------------------------------------
bbContag+bbED+bbENN_MN
bbContag+bbED+bbLPI
bbContag+bbED+bbLSI
bbContag+bbENN_MN+bbED
bbContag+bbENN_MN+bbLPI

etc.
0
 

Author Comment

by:justearth
ID: 22704300
pepr:
Exporting to csv would be acceptable, so would a text file.

Thanks,
JE
0
 
LVL 81

Expert Comment

by:byundt
ID: 22704396
JE,
There are only 15 possible answers for four words in addition to the fixed one. If you put the formula in row 1 and copy down through row 15, all are listed. The invariant word is listed in row 16, and duplicates in the following rows.

As an alternative, here is a macro that will enumerate the possibilities in a column immediately below your words. Select the words, then run the macro.

To install a sub in a regular module sheet:
1) ALT + F11 to open the VBA Editor
2) Use the Insert...Module menu item to create a blank module sheet
3) Paste the suggested code in this module sheet
4) ALT + F11 to return to the spreadsheet

To run a sub or macro:
5) ALT + F8 to open the macro window
6) Select the macro
7) Click the "Run" button

Optional steps to assign a shortcut key to your macro:
8) Repeat steps 5 & 6, then press the "Options" button
9) Enter the character you want to use (Shift + character will have fewer conflicts with existing shortcuts)
10) Enter some descriptive text telling what the macro does in the "Description" field
11) Click the "OK" button

If the above procedure doesn't work, then you need to change your macro security setting. To do so, open the Tools...Macro...Security menu item. Choose Medium, then click OK.

Brad

Sub Combinatrix()
'Forms all the combinations of one fixed value with varying numbers of other values
'Uses binary counting method
Dim i As Long, j As Long, k As Long, N As Long, NN As Long
Dim v As Variant, vInputs As Variant, vResults As Variant
Dim s As String
N = Application.CountA(Selection.Value)
ReDim vInputs(1 To N)
For i = 1 To N
    If Selection.Cells(i) <> "" Then
        j = j + 1
        vInputs(j) = Selection.Cells(i)
    End If
Next
ReDim Preserve vInputs(1 To j)
 
NN = 2 ^ (N - 1) - 1
ReDim vResults(1 To NN, 1 To 1)
For i = 1 To NN
    vResults(i, 1) = vInputs(1)
    For j = 2 To N
        k = IIf((i Mod 2 ^ (j - 1)) >= 2 ^ (j - 2), 1, 0)
        If k = 1 Then vResults(i, 1) = vResults(i, 1) & "+" & vInputs(j)
    Next
Next
Selection.Offset(1, 0).Resize(NN, 1).Value = vResults
End Sub

Open in new window

0
 

Author Comment

by:justearth
ID: 22704427
Pepr:
Also, from above I asked "I need to create a list from these numbers that always contain the value from column1 and then all possible combination of the values from the remaining columns' values" The python script does not do this, as is. Can this be implemented or would it be easier to go through and select the ones that fit this manually?

Also, can this be set up to work with a list of lists? What I mean is if you look at my spreadsheet example I have several rows I'd like to do this on, but each has different string values for among the cells in its row?

Thanks,
JE
0
 

Author Comment

by:justearth
ID: 22704581
byundt:

This macro works well. My only question is, can it somehow place the result in a new sheet, or somewhere else.

The way my values are setup now I several rows with values that are right after one another. If you look at my example xls above you'll see what I mean. With the current incarnation of this macro it will replace the first column for the subsequent rows.

So, I guess, is there way to make it run all the rows and then save them as columns (e.g. row1's result = column a, row2's result = columnb, etc) on a new sheet? If this is not easily done, I will just do the rows one by one and cut and paste.

Thank you kindly,
JE
0
 
LVL 81

Accepted Solution

by:
byundt earned 400 total points
ID: 22704726
JE,
Try the following tweak to the original macro. It puts the results on worksheet Sheet2 in adjacent columns.
Brad
Sub Combinatrix()
'Forms all the combinations of one fixed value with varying numbers of other values
'Uses binary counting method
Dim i As Long, iCol As Long, j As Long, k As Long, N As Long, NN As Long
Dim v As Variant, vInputs As Variant, vResults As Variant
Dim rw As Range, rg As Range
Dim s As String
Set rg = Selection
For Each rw In Selection.Rows
    N = Application.CountA(rw)
    ReDim vInputs(1 To N)
    j = 0
    For i = 1 To N
        If rw.Cells(i) <> "" Then
            j = j + 1
            vInputs(j) = rw.Cells(i)
        End If
    Next
    ReDim Preserve vInputs(1 To j)
    
    NN = 2 ^ (N - 1) - 1
    ReDim vResults(1 To NN, 1 To 1)
    For i = 1 To NN
        vResults(i, 1) = vInputs(1)
        For j = 2 To N
            k = IIf((i Mod 2 ^ (j - 1)) >= 2 ^ (j - 2), 1, 0)
            If k = 1 Then vResults(i, 1) = vResults(i, 1) & "+" & vInputs(j)
        Next
    Next
    iCol = iCol + 1 'Put the results on Sheet2 in adjacent columns
    Worksheets("Sheet2").Cells(1, iCol).Resize(NN, 1).Value = vResults
Next
End Sub

Open in new window

0
 

Author Comment

by:justearth
ID: 22704919

byundt:
Awesome.

Thanks,
JE
0
 

Author Closing Comment

by:justearth
ID: 31505518
Thanks.
0
 
LVL 81

Expert Comment

by:byundt
ID: 22705053
JE,
Thanks for the grade!
Brad
0
 
LVL 29

Expert Comment

by:pepr
ID: 22709036
justearth> Pepr: Also, from above I asked "I need to create a list from these numbers
justearth> that always contain the value from column1 and then all possible combination
justearth> of the values from the remaining columns' values" The python script
justearth> does not do this, as is. Can this be implemented

Yes. The script solves a single row. But it can be wrapped into another loop that goes through the rows.

The modification for preserving the first value is also easy. I guess, you already have your solution. Anyway, the core of the code would be like

row = ['bbContag', 'bbED', 'bbENN_MN', 'bbLPI', 'bbLSI']

for row in get_the_row_here():
    elem1 = row[0]
    rowtail = row[1:]

    here put the above loop

0
 

Author Comment

by:justearth
ID: 22714014
pepr:
Thank you kindly for the follow-up. I really appreciate it.

Cheers,
JE
0
 

Author Comment

by:justearth
ID: 22714070
Hello,
If interested I have a follow-up question:

http://www.experts-exchange.com/Software/Office_Productivity/Office_Suites/MS_Office/Excel/Q_23813830.html

I'd like to change the output format.

Thanks again,
JE
0

Featured Post

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Freeze panes is an option within all variants of Excel to enable parts of a sheet to remain stationary when the cursor is in another part of the sheet. This is a very useful feature which is overlooked or under used.
When you see single cell contains number and text, and you have to get any date out of it seems like cracking our heads.
This Micro Tutorial will demonstrate how to use longer labels with horizontal bar charts instead of the vertical column chart.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

856 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question