views:

1751

answers:

4

OK, so basically what I want is a program that would print every combination of a set of variables to a different line of a text file, creating a word list.

for example, print all binary number combinations possible up to for 1, 2, and 3 digits:

0 1

00 01 10 11

000 001 010 011 100 101 110 111

But putting each one of those answers on a separate line and saving all results for 1 digit, 2 digits, and 3 digits to a single text file.

Is there a simple program that can be written to accomplish this? I just don't want to type every combo possible, which would get long very quickly. I would imagine that there is a pretty easy way to do this in python.

+1  A: 

It shouldn't be too hard in most languages. Does the following pseudo-code help?

for(int i=0; i < 2^digits; i++)
{
     WriteLine(ToBinaryString(i));
}
SoloBold
That works for binary digit strings - and can probably be made to work for most digit strings. It won't easily adapt to more arbitrary things, such as a set of words.
Jonathan Leffler
If you treat each word of set as an digit in an n-base number system,it'll work.
Vardhan Varma
+2  A: 
# Given two lists of strings, return a list of all ways to concatenate
# one from each.
def combos(xs, ys):
    return [x + y for x in xs for y in ys]

digits = ['0', '1']
for c in combos(digits, combos(digits, digits)):
    print c

#. 000
#. 001
#. 010
#. 011
#. 100
#. 101
#. 110
#. 111
Darius Bacon
This gets storage intensive if the sets are large - but you can probably effectively argue that storage to disk gets expensive at the same time.
Jonathan Leffler
There's probably a way to address that with a generator comprehension in place of the list comprehension, but that'd require making a copy of the input iterator. (You can only go through an iterator once. Dang Python for not being Haskell!)
Darius Bacon
So instead I'd write the obvious recursive code with no generators.
Darius Bacon
+2  A: 

A basic function to produce all the permutations of a list is given below. In this approach, permutations are created lazily by using generators.

def perms(seq):
    if seq == []:
        yield []
    else:
        res = []
        for index,item in enumerate(seq):
            rest = seq[:index] + seq[index+1:]
            for restperm in perms(rest):
                yield [item] + restperm

alist = [1,1,0]
for permuation in perms(alist):
    print permuation
Andrew Walker
Did you intend to use [1,1,0] instead of just [1,0]? If so, please explain.
Jonathan Leffler
The question seems to be about powersets, not permutations. This code produces n! results, not 2**n results.
Darius Bacon
A: 

A naïve solution which solves the problem and is general enough for any application you might have is this:

def combinations(words, length):
    if length == 0:
        return []
    result = [[word] for word in words]
    while length > 1:
        new_result = []
        for combo in result:
            new_result.extend(combo + [word] for word in words)
        result = new_result[:]
        length -= 1
    return result

Basically, this gradually builds up a tree in memory of all the combinations, and then returns them. It is memory-intensive, however, and so is impractical for large-scale combinations.

Another solution for the problem is, indeed, to use counting, but then to transform the numbers generated into a list of words from the wordlist. To do so, we first need a function (called number_to_list()):

def number_to_list(number, words):
    list_out = []
    while number:
        list_out = [number % len(words)] + list_out
        number = number // len(words)
    return [words[n] for n in list_out]

This is, in fact, a system for converting decimal numbers to other bases. We then write the counting function; this is relatively simple, and will make up the core of the application:

def combinations(words, length):
    numbers = xrange(len(words)**length)
    for number in numbers:
        combo = number_to_list(number, words)
        if len(combo) < length:
            combo = [words[0]] * (length - len(combo)) + combo
        yield combo

This is a Python generator; making it a generator allows it to use up less RAM. There is a little work to be done after turning the number into a list of words; this is because these lists will need padding so that they are at the requested length. It would be used like this:

>>> list(combinations('01', 3))
[['0', '0', '0'], ['0', '0', '1'],
['0', '1', '0'], ['0', '1', '1'],
['1', '0', '0'], ['1', '0', '1'],
['1', '1', '0'], ['1', '1', '1']]

As you can see, you get back a list of lists. Each of these sub-lists contains a sequence of the original words; you might then do something like map(''.join, list(combinations('01', 3))) to retrieve the following result:

['000', '001', '010', '011', '100', '101', '110', '111']

You could then write this to disk; a better idea, however, would be to use the built-in optimizations that generators have and do something like this:

fileout = open('filename.txt', 'w')
fileout.writelines(
    ''.join(combo) for combo in combinations('01', 3))
fileout.close()

This will only use as much RAM as necessary (enough to store one combination). I hope this helps.

zvoase