Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

All possibilities to split a list into two lists

I have a list with some elements and want to iterate over all possible ways to divide this list into two lists. By that I mean all combinations, so the order doesn't matter (i.e. Element 1 and 3 could be in the one list and Element 2 in the other). Currently I do it like this, where facs is my initial list:

patterns = []
for i in range(2**(len(facs)-1)):
    pattern = []
    for j in range((len(facs)-1)):
        pattern.append(i//(2**j)%2)
    patterns.append(pattern)

for pattern in patterns:
    l1 = [facs[-1]]
    l2 = []
    for i in range(len(pattern)):
        if pattern[i] == 1:
            l1.append(facs[i])
        else:
            l2.append(facs[i])

So I basically create a list of length 2^(len(facs)-1) and fill it with every possible combination of ones and zeros. I then 'overlay' every pattern with facs, except for the last element of facs which is always in l1, as I'd otherwise get every result twice, as I handle two lists the same, no matter what lists is l1 or l2.

Is there a faster and more elegant (shorter/more pythonic) way to do this?

like image 456
PattuX Avatar asked Nov 20 '16 21:11

PattuX


People also ask

Can you split a list of lists in Python?

To split the elements of a list in Python: Use a list comprehension to iterate over the list. On each iteration, call the split() method to split each string. Return the part of each string you want to keep.

How do you generate all possible combinations of two lists in Python?

The unique combination of two lists in Python can be formed by pairing each element of the first list with the elements of the second list. Method 1 : Using permutation() of itertools package and zip() function. Approach : Import itertools package and initialize list_1 and list_2.

Can lists be split?

A list can be split based on the size of the chunk defined. This means that we can define the size of the chunk. If the subset of the list doesn't fit in the size of the defined chunk, fillers need to be inserted in the place of the empty element holders.


2 Answers

itertools has product() which could be used to generate the masks and izip() which could combine the lists for easy filtering. As a bonus, since they return iterators, they don't use much memory.

from itertools import *

facs = ['one','two','three']

l1 = []
l2 = []
for pattern in product([True,False],repeat=len(facs)):
    l1.append([x[1] for x in izip(pattern,facs) if x[0]])
    l2.append([x[1] for x in izip(pattern,facs) if not x[0]])
like image 95
Ouroborus Avatar answered Oct 21 '22 03:10

Ouroborus


Just extending @Ouroborus solution using filters and keeping the results together:

import itertools as it

# itertools recipe
def partition(pred, iterable):
    t1, t2 = it.tee(iterable)
    return it.filterfalse(pred, t1), filter(pred, t2)

>>> facs = ['one','two','three']
>>> [[[x[1] for x in f] for f in partition(lambda x: x[0], zip(pattern, facs))]
...  for pattern in product([True, False], repeat=len(facs))]
[[[], ['one', 'two', 'three']],
 [['three'], ['one', 'two']],
 [['two'], ['one', 'three']],
 [['two', 'three'], ['one']],
 [['one'], ['two', 'three']],
 [['one', 'three'], ['two']],
 [['one', 'two'], ['three']],
 [['one', 'two', 'three'], []]]
like image 34
AChampion Avatar answered Oct 21 '22 02:10

AChampion