Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

subtuples for a tuple

I wish to yield the following:

(('A',), ('B',), ('C',), ('D',))
(('A',), ('B',), ('C','D'))
(('A',), ('B','C'), ('D',))
(('A',), ('B','C','D'))
(('A','B'), ('C',), ('D',))
(('A','B'), ('C','D'))
(('A','B','C'), ('D',))
(('A','B','C','D'),)

when calling sub_combinations(('A', 'B', 'C', 'D'))

Here's my attempt but it doesn't work:

def sub_combinations(segment):
   for i in range(1, len(segment)):
      for j in sub_combinations(segment[i:]):
         yield segment[:i]+j 
      yield segment 

but I think I'm on the right track.

Additionally, I'd like to have a second argument called limit which limits the size of the sub tuples, for example sub_combinations(('A', 'B', 'C', 'D'), 2) would give:

(('A',), ('B',), ('C',), ('D',))
(('A',), ('B',), ('C','D'))
(('A',), ('B','C'), ('D',))
(('A','B'), ('C',), ('D',))
(('A','B'), ('C','D'))

I'm using python 3.

like image 252
Baz Avatar asked Jan 27 '14 15:01

Baz


People also ask

Can you use a for loop on a tuple?

Loop Through a TupleYou can loop through the tuple items by using a for loop.

Can we use split function in tuple?

In order to split it in four sub-tuple of three elements each, slice a tuple of three successive elements from it and append the segment in a lis. The result will be a list of 4 tuples each with 3 numbers.

Can you do indexing for tuples?

Tuple Indexing We can access elements in a tuple in the same way as we do in lists and strings. Hence, we can access elements simply by indexing and slicing. Furthermore, the indexing is simple as in lists, starting from the index zero.

Can a tuple be mutated?

Once a tuple is created, you cannot change its values. Tuples are unchangeable, or immutable as it also is called. But there is a workaround. You can convert the tuple into a list, change the list, and convert the list back into a tuple.


2 Answers

Handle base case - when segment is empty:

def sub_combinations(segment, size=0):
    if segment == ():
        yield ()
        return
    stop = min(size or len(segment), len(segment))
    for i in range(1, stop + 1):
        for j in sub_combinations(segment[i:], size):
            yield (segment[:i],) + j

Example usage:

>>> for x in sub_combinations(('A', 'B', 'C', 'D')):
...     print(x)
...
(('A',), ('B',), ('C',), ('D',))
(('A',), ('B',), ('C', 'D'))
(('A',), ('B', 'C'), ('D',))
(('A',), ('B', 'C', 'D'))
(('A', 'B'), ('C',), ('D',))
(('A', 'B'), ('C', 'D'))
(('A', 'B', 'C'), ('D',))
(('A', 'B', 'C', 'D'),)

>>> for x in sub_combinations(('A', 'B', 'C', 'D'), 2):
...     print(x)
...
(('A',), ('B',), ('C',), ('D',))
(('A',), ('B',), ('C', 'D'))
(('A',), ('B', 'C'), ('D',))
(('A', 'B'), ('C',), ('D',))
(('A', 'B'), ('C', 'D'))
like image 123
falsetru Avatar answered Oct 23 '22 07:10

falsetru


In case you also can live with lists instead of tuples (or aren't afraid of converting them later), you can use this:

def subtuples(t):
  for i in range(1<< (len(t)-1)):
    result = [ [ t[0] ] ]
    for j in range(len(t)-1):
      if (1<<j) & i:
        result[-1].append(t[j+1])
      else:
        result.append([ t[j+1] ])
    yield result

for x in subtuples(('a', 'b', 'c', 'd')):
  print(x)
like image 41
Alfe Avatar answered Oct 23 '22 08:10

Alfe