生成唯一数字组合的方法

时间:2018-01-16 09:50:14

标签: python

我有一个数组:

A = [0,2,5,6]
B = [5,6,8,9]
C = [6,7,8,9]

我想写两个函数,下面是详细信息:

问题1 当我传入上面定义的任何数组时,我按顺序方式得到数字组合(按顺序意义,n + 1)。所以期望的输出是:

ResultA = [[0],[2],[5],[6],[5,6]]
ResultB = [[5],[6],[8],[9],[5,6],[8,9]]
ResultC = [[6],[7],[8],[9],[6,7],[7,8],[8,9],[6,7,8],[7,8,9],[6,7,8,9]]

以下是我尝试的内容:

sorted_ids = sorted(number_collection)
combinations = [sorted_ids[j: j + i] for i in range(1, len(sorted_ids)) for j in range(len(sorted_ids) - i + 1)]

问题是它适用于数组C,但与其他数组的效果不佳。

问题2 problem 1的结果是此问题的输入。问题是我想要存在于数字的唯一元素上的组合。 (我不确定我能用正确的方法解释它),下面是所需的输出:

FinalResultA = [[0],[2],[5,6]]
FinalResultB = [[5,6],[8,9]]
FinalResultC = [[6,7,8,9]]

我可以使用哪种方法(以性能为导向)帮助吗?

2 个答案:

答案 0 :(得分:1)

这是一种相当有效的方法,虽然它确实需要O(N)辅助空间,但如果运行次数很少那么它不应该是重要的:

from itertools import groupby

def ngrams(seq):
    stop = len(seq)+1
    for n in range(2, stop):
        for i in range(stop - n):
            yield seq[i:i+n]

def get_combos(seq):
    runs = []
    for _, g in groupby(enumerate(seq), lambda x:x[1]-x[0]):
        run = [a for _, a in g]
        for x in run:
            yield [x]
        if len(run) > 1:
            runs.append(run)
    for run in reversed(runs):
        yield from ngrams(run)

注意,这使用this classic approach对连续的整数进行分组。它迭代连续整数组,"运行",并产生任何单个整数作为单元素列表。如果运行时间长于1,我将其添加到运行列表中。最后,你反过来迭代运行列表,产生" n-gram",从订单2到订单len(运行)。

行动中:

>>> A = [0,2,5,6]
>>> B = [5,6,8,9]
>>> C = [6,7,8,9]
>>> list(get_combos(A))
[[0], [2], [5], [6], [5, 6]]
>>> list(get_combos(B))
[[5], [6], [8], [9], [8, 9], [5, 6]]
>>> list(get_combos(C))
[[6], [7], [8], [9], [6, 7], [7, 8], [8, 9], [6, 7, 8], [7, 8, 9], [6, 7, 8, 9]]

注意

get_combos假设输入已排序

编辑

然而,对于:

>>> D = [6,7,9,12,13,14,20,21,30]

这将产生:

>>> list(get_combos(D))
[[6], [7], [9], [12], [13], [14], [20], [21], [30], [20, 21], [12, 13], [13, 14], [12, 13, 14], [6, 7]]

I.E。,3序列在后续运行的2个序列产生之前开始。如果希望在n + 1个len序列之前产生所有n-len序列,请使用以下方法:

from itertools import groupby

def ngrams(seq, max_len):
    curr = seq
    for n in range(1, max_len + 1):
        nxt = []
        for run in curr:
            run_len = len(run)
            if run_len > n:
                nxt.append(run)
            for i in range(run_len + 1 - n):
                yield run[i:i+n]
        curr = nxt

def _sub_index(t):
    return t[1] - t[0]

def get_consecutive_runs(seq):
    grouped = groupby(enumerate(seq), _sub_index)
    for _, g in grouped:
        yield [a for _, a in g]


def get_combos(seq):
    runs = list(get_consecutive_runs(seq))
    max_len = max(map(len, runs))
    yield from ngrams(runs, max_len)

得到以下结果:

>>> list(get_combos(D))
[[6], [7], [9], [12], [13], [14], [20], [21], [30], [6, 7], [12, 13], [13, 14], [20, 21], [12, 13, 14]]

答案 1 :(得分:0)

这是您在一个没有任何外部库的函数中的两个解决方案:

A = [0,2,5,6]
B = [5,6,8,9]
C= [6,7,8,9]

def finding_sequence(list_1):
    sub_list = []
    for j, i in enumerate(list_1):

        try:
            if list_1[j] - list_1[j - 1] == 1:
                sub_list.append((list_1[j - 1], list_1[j]))
            else:
                sub_list.append('_pos')


        except IndexError:

            pass

    sub_final_result = []
    check_result=[]
    if '_pos' not in sub_list[1:]:
        for i in sub_list[1:]:
            for k in i:
                if k not in sub_final_result:
                    sub_final_result.append(k)
                    check_result.append(k)

    else:
        for i in sub_list:
            if i != '_pos':
                sub_final_result.append(i)
                for i1 in i:
                    check_result.append(i1)


    for i1 in list_1:
        if i1 not in check_result:
            sub_final_result.append([i1])

    return sub_final_result

测试用例:

print(finding_sequence(A))

输出:

[(5, 6), [0], [2]]

第二

print(finding_sequence(B))

输出:

[(5, 6), (8, 9)]

P.S:一个请求:如果我的回答对您有帮助,请不要接受,只需使用它。