Algorithm to generate (not quite) spanning set in Python

后端 未结 3 580
南笙
南笙 2020-12-18 16:29

This follows on from this question:

Algorithm to generate spanning set

Given this input: [1,2,3,4]

I\'d like to generate this set of sets in python:<

相关标签:
3条回答
  • 2020-12-18 16:49

    Adjusting one of the solution from Python: show all possible groupings of a list:

    from itertools import combinations
    
    def cut(lst, indexes):
        last = 0
        for i in indexes:
            yield lst[last:i]
            last = i
        yield lst[last:]
    
    def generate(lst, n):
        for indexes in combinations(list(range(1,len(lst))), n - 1):
            yield list(cut(lst, indexes))
    
    data = [1,2,3,4]
    
    for i in range(1, len(data)+1):  # the only difference is here
        for g in generate(data, i):
            print(g)
    
    """
    [[1, 2, 3, 4]]
    [[1], [2, 3, 4]]
    [[1, 2], [3, 4]]
    [[1, 2, 3], [4]]
    [[1], [2], [3, 4]]
    [[1], [2, 3], [4]]
    [[1, 2], [3], [4]]
    [[1], [2], [3], [4]]
    """
    
    0 讨论(0)
  • 2020-12-18 16:57

    You might also enjoy a recursive solution:

    def span(lst):
      yield [lst]
      for i in range(1, len(lst)):
        for x in span(lst[i:]):
          yield [lst[:i]] + x
    

    Explanation

    We exploit recursion here to break the problem down. The approach is the following:

    For every list, the whole list is a valid spanning: [1,2,3,4] => [[1,2,3,4]].

    For every list that is longer than size 1, we can use the first item as a group and then apply the same algorithm on the remaining list to get all the combined results:

    [1,2,3] => 
      [[1]] + [[2], [3]]  # => [[1], [2], [3]]
      [[1]] + [[2,3]]     # => [[1], [2,3]]
    

    For every list that is longer than size 2, we can just as well use the first two items as a group and then apply the same algorithm on the remaining list and combine the results:

    [1,2,3,4,5] =>
      [[1,2]] + [[3], [4], [5]]  # => [[1,2], [3], [4], [5]]
      [[1,2]] + [[3,4], [5]]     # => [[1,2], [3,4], [5]]
      [[1,2]] + [[3], [4,5]]     # => [[1,2], [3], [4,5]]
      [[1,2]] + [[3,4,5]]        # => [[1,2], [3,4,5]]
    

    We can see that the possible combinations on the right side are indeed all possible groupings of the remainder of the list, [3,4,5].

    For every list that is longer than ... etc. Thus, the final algorithm is the following:

    1. yield the whole list (it is always a valid spanning, see above)
    2. For every possible splitting of the list, yield the left-hand part of the list combined with all possible spannings of the right-hand part of the list.

    yield is a special keyword in Python that make the function a generator, which means that it returns a iterable object that can be used to enumerate all results found. You can transform the result into a list using the list constructor function: list(span([1,2,3,4])).

    0 讨论(0)
  • 2020-12-18 17:00
    import itertools
    a = [1, 2, 3, 4]
    n = len(a)
    for num_splits in range(n):
        for splits in itertools.combinations(range(1, n), num_splits):
            splices = zip([0] + list(splits), list(splits) + [n])
            print([a[i:j] for i, j in splices])
    

    prints

    [[1, 2, 3, 4]]
    [[1], [2, 3, 4]]
    [[1, 2], [3, 4]]
    [[1, 2, 3], [4]]
    [[1], [2], [3, 4]]
    [[1], [2, 3], [4]]
    [[1, 2], [3], [4]]
    [[1], [2], [3], [4]]
    
    0 讨论(0)
提交回复
热议问题