简体   繁体   中英

Is there a simple way in python to find all ways to pick consecutive numbers?

Sorry about the confusingly worded title, I'm fairly new to python development and I'm not sure how to approach the following problem.

I'm trying to solve an allocation style problem which I have boiled down to the following.

Take the following example of a nested list:

[[0, 3], [0, 1, 2], [3], [4], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]

I need to find all ways to select one item from each sublist such that all integers 0 to 5 are selected.

In this case one way of doing so is:

  • 0 -> 0
  • 1 -> 2
  • 2 -> 3
  • 3 -> 4
  • 4 -> 1
  • 5 -> 5

Another way would be

  • 0 -> 0
  • 1 -> 2
  • 2 -> 3
  • 3 -> 4
  • 4 -> 5
  • 5 -> 1

I would also need this to be generalisable to longer lists with more numbers.

You could try something like below. ( Note that I have slightly modified the input list such that all the numbers from 0 through 5 is selected)

nested_list = [[0, 3], [0, 1, 2], [3], [4], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [3, 4, 5], [5, 9, 10]]
iter_obj = iter(nested_list)

for i, l in enumerate(iter_obj):
    is_found = False
    while not is_found:
        if i in l:
            print(f'selected {i} from list {l}')
            is_found = True
        else:
            print(f'ignoring list {l} as it does not contain {i}')
            l = next(iter_obj)

Result

selected 0 from list [0, 3]
selected 1 from list [0, 1, 2]
ignoring list [3] as it does not contain 2
ignoring list [4] as it does not contain 2
selected 2 from list [0, 1, 2, 3, 4, 5]
selected 3 from list [0, 1, 2, 3, 4, 5]
selected 4 from list [3, 4, 5]
selected 5 from list [5, 9, 10]

This script prints every combination that satisfies the criteria. The values in input list must be in range <0, lenght(input list)> :

lst = [[0, 3], [0, 1, 2], [3], [4], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]

def find_combination(lst, idxs=[]):
    s = []
    for i, idx in enumerate(idxs):
        if 0 <= lst[i][idx] <= len(lst):
            s.append(lst[i][idx])

    if len(s) == len(lst) and len(set(s)) == len(lst):
        yield s

    for i, idx in enumerate(lst):
        if len(idxs) == i:
            for ii in range(len(lst[i])):
                yield from find_combination(lst, idxs + [ii])

for c in find_combination(lst):
    print(c)

Prints:

[0, 1, 3, 4, 2, 5]
[0, 1, 3, 4, 5, 2]
[0, 2, 3, 4, 1, 5]
[0, 2, 3, 4, 5, 1]

With the python builtin itertools module you can easily accomplish a different kind of combinatorics fast and memory efficient like:

  • cartesian product product('ABCD', repeat=2) -> AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
  • permutation permutations('ABCD', 2) -> AB AC AD BA BC BD CA CB CD DA DB DC
  • combination combinations('ABCD', 2) -> AB AC AD BC BD CD
  • combination with replacement combinations_with_replacement('ABCD', 2) -> AA AB AC AD BB BC BD CC CD DD

and even more, like "infinite iterators" and "iterators terminating on the shortest input sequence".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM